Pinata Cleaning
Published: 2022-01-09 20:17:12

---
title: Pinata Cleaning
published: true
date: 2022-01-09 13:04:00 UTC
tags: 
canonical_url: https://kevincox.ca/2022/01/09/pinata-cleaning/
---

<main><p>I use <a href="https://www.pinata.cloud/">Pinata</a> for hosting a number of websites on IPFS. However, due to their double-charging of similar pins, I need to clean up old copies of my sites to avoid high costs. I am just sharing a couple of simple scripts that work for me and could easily be adapted to other simple cleanups.</p>
<h2 id="setup"><a href="https://kevincox.ca/2022/01/09/pinata-cleaning/#setup">Setup</a></h2>
<p>You need an API key to modify your account. Set up a shell variable with your key:</p>
<p>You may want to do something to keep this out of your shell history. For example, I have configured my shell so that I can prefix commands with a space to prevent them from being written to disk.</p>
<div><pre><code><span>pinata_auth</span><span>=</span><span>'-HAuthorization: Bearer YOUR_PINATA_JWT_HERE'</span>
</code></pre></div>
<h2 id="scripts"><a href="https://kevincox.ca/2022/01/09/pinata-cleaning/#scripts">Scripts</a></h2>
<h3 id="delete-by-regex"><a href="https://kevincox.ca/2022/01/09/pinata-cleaning/#delete-by-regex">Delete by Regex</a></h3>
<p>First preview the paths to delete:</p>
<div><pre><code>curl <span>$pinata_auth</span> <span>\</span>
	<span>'https://api.pinata.cloud/data/pinList?status=pinned&amp;pageLimit=1000'</span> <span>\</span>
	| jq <span>-r</span> <span>'
		.rows[]
		| select(.metadata.name | match("^_dnslink\\."))
	'</span>
</code></pre></div>
<p>Then actually perform the deletion.</p>
<div><pre><code>curl <span>$pinata_auth</span> <span>\</span>
	<span>'https://api.pinata.cloud/data/pinList?status=pinned&amp;pageLimit=1000'</span> <span>\</span>
	| jq <span>-r</span> <span>'
		.rows[]
		| select(.metadata.name | match("^_dnslink\\."))
		| "https://api.pinata.cloud/pinning/unpin/\(.ipfs_pin_hash)"
	'</span> <span>\</span>
	| xargs <span>-n1</span> <span>--</span> curl <span>-iXDELETE</span> <span>--retry</span> 2 <span>$pinata_auth</span>
</code></pre></div>
<h3 id="delete-old-versions"><a href="https://kevincox.ca/2022/01/09/pinata-cleaning/#delete-old-versions">Delete old Versions</a></h3>
<p>I upload new versions of sites with the same name. In this case I want to delete all but the last couple of versions of each site.</p>
<div><pre><code>curl <span>$pinata_auth</span> <span>\</span>
	<span>'https://api.pinata.cloud/data/pinList?status=pinned&amp;pageLimit=1000'</span> <span>\</span>
	| jq <span>-r</span> <span>'
		.rows
		| group_by(.metadata.name)
		| .[]
		| sort_by(.date_pinned)
		| .[0:-3]
		| "https://api.pinata.cloud/pinning/unpin/\(.[].ipfs_pin_hash)"
	'</span> <span>\</span>
	| xargs <span>-n1</span> <span>--</span> curl <span>-iXDELETE</span> <span>--retry</span> 2 <span>$pinata_auth</span>
</code></pre></div>
<p>This one is a bit complicated. Here is a quick overview how it works.</p>
<ol>
<li>Group by name.</li>
<li>Separate each group into its own item in the stream.</li>
<li>Sort by the date pinned to Pinata.</li>
<li>Take all but the last 3. If there is less than three none will be selected.</li>
<li>Generate the unpin URLs.</li>
</ol>
<h2 id="other-notes"><a href="https://kevincox.ca/2022/01/09/pinata-cleaning/#other-notes">Other Notes</a></h2>
<ol>
<li>Pinata only supports deleting a single pin at a time and has a rate limit. The <code>--retry</code> flag to curl will handle the rate limiting for us but deleting a lot of pins can still take a long time.</li>
<li>I make no attempt to handle paging. For the examples provided you can keep re-running the whole pipeline as long as the number of paths that you want to keep is less than 1000. However, if you have more than 1000 live paths you will need to handle paging.</li>
</ol></main>