@snap-pink/sdk
v0.9.0
Published
Full-platform SDK for the snap.pink QR API.
Maintainers
Readme
@snap-pink/sdk
Full-platform SDK for the snap.pink QR code and URL shortener API.
Default API base URL: https://api.snap.pink
Install
npm install @snap-pink/sdkQuick start
import { createSnapPinkClient } from "@snap-pink/sdk";
const client = createSnapPinkClient({
apiKey: process.env.SNAP_PINK_API_KEY,
});
// Shorten a URL
const link = await client.createLink({
url: "https://example.com/long-page",
customSlug: "my-link",
});
console.log(link.shortUrl); // https://go.snap.pink/my-link
// Create a dynamic QR code
const qrCode = await client.createQrCode({
name: "Spring Campaign",
kind: "dynamic",
currentDestinationUrl: "https://brand.com/spring",
payload: { type: "url", url: "https://brand.com/spring" },
analyticsEnabled: true,
customSlug: "spring-2026",
expiresAt: "2026-06-01T00:00:00Z",
utmParams: { source: "qr", medium: "print", campaign: "spring" },
});Free static QR (no auth)
import { createStaticQr, createStaticQrSvg } from "@snap-pink/sdk";
const qr = await createStaticQr({ url: "https://snap.pink" });
const svg = await createStaticQrSvg({ payloadType: "text", text: "Hello" });Free URL shortener (no auth)
import { shortenUrl } from "@snap-pink/sdk";
const result = await shortenUrl("https://example.com/very/long/page");
console.log(result.shortUrl); // https://go.snap.pink/a3f7b2c1
// Or with an object:
const result2 = await shortenUrl({ url: "https://example.com/page" });Free short links are permanent, uneditable, and have no analytics.
Every URL is screened against Google Web Risk and a domain blocklist before a short link is created.
For editable links with tracking, use client.createLink() (requires auth).
Error handling
All API errors throw a SnapPinkError with code and status fields:
import { shortenUrl, SnapPinkError } from "@snap-pink/sdk";
try {
await shortenUrl("https://suspicious-site.example");
} catch (err) {
if (err instanceof SnapPinkError) {
console.error(err.code); // "blocked_domain", "safe_browsing:MALWARE", etc.
console.error(err.status); // 422
console.error(err.message); // "This URL is not allowed."
}
}URL safety error codes (apply to all endpoints that accept a destination URL — free shortener, paid links, and QR codes):
| Code | Meaning |
|------|---------|
| invalid_protocol | URL must start with http:// or https:// |
| url_too_long | URL exceeds 2048 characters |
| invalid_url | Malformed URL |
| self_referential | Cannot shorten snap.pink URLs |
| blocked_domain | Domain is on the blocklist (adult, spam, shortener chains) |
| blocked_content | URL path contains blocked keywords |
| safe_browsing:* | Flagged by Google Web Risk (malware, phishing, etc.) |
| rate_limited | Too many requests (5/hour, 15/day per IP) |
Report abusive links (no auth)
import { reportLink } from "@snap-pink/sdk";
await reportLink("a3f7b2c1", "Phishing attempt");Reports are reviewed and actioned by the platform.
API reference
Links (URL shortener)
const link = await client.createLink({ url, customSlug?, expiresAt?, password?, tags? });
const { data, hasMore } = await client.listLinks({ limit?, cursor?, status?, search? });
await client.updateLink({ linkId, url?, customSlug?, expiresAt?, password? });
await client.deleteLink(linkId);QR codes
await client.createQrCode({ name, kind, payload, design?, customSlug?, ... });
await client.getQrCode(qrCodeId);
const { data, hasMore } = await client.listQrCodes({ limit?, cursor?, kind?, tag? });
await client.updateQrCode({ qrCodeId, currentDestinationUrl?, status?, ... });
await client.deleteQrCode(qrCodeId); // soft delete (archive)
await client.permanentlyDeleteQrCode(qrCodeId); // permanent delete
await client.duplicateQrCode(qrCodeId, name?);
await client.batchQrCodes({ operation, qrCodeIds, ... });Routing rules
await client.listRoutingRules(qrCodeId);
await client.createRoutingRule({ qrCodeId, condition, destinationUrl, priority? });
await client.updateRoutingRule({ ruleId, qrCodeId, condition?, destinationUrl? });
await client.deleteRoutingRule(ruleId, qrCodeId);
await client.reorderRoutingRules(qrCodeId, ruleIds);Condition types: geo_country, geo_region, device, os, language, ab_split, time_window, date_range.
Retargeting pixels
await client.listPixels();
await client.createPixel({ name, platform, pixelId });
await client.updatePixel({ pixelId, name?, isEnabled? });
await client.deletePixel(pixelId);Platforms: meta_pixel, google_ads, tiktok, linkedin, twitter, custom.
Webhooks
await client.listWebhooks();
await client.createWebhook({ url, secret, events });
await client.updateWebhook({ webhookId, url?, events?, isEnabled? });
await client.deleteWebhook(webhookId);
await client.testWebhook(webhookId);Events: scan, link.click, link.created, link.updated.
UTM templates
await client.listUtmTemplates();
await client.createUtmTemplate({ name, source?, medium?, campaign?, term?, content? });
await client.updateUtmTemplate({ templateId, name?, source?, ... });
await client.deleteUtmTemplate(templateId);Bio pages (link-in-bio)
await client.listBioPages();
await client.createBioPage({ slug, title, links, theme?, socialLinks? });
await client.updateBioPage({ bioPageId, title?, links?, isPublished? });
await client.deleteBioPage(bioPageId);
await client.addBioPageQr(bioPageId); // retroactively create a linked QR codeDiscovery
await client.publishToDiscovery({ qrCodeId, enabled, title?, category?, tags?, publisherDisplayName? });
await client.getDiscoveryListing(qrCodeId);Folders
await client.listFolders();
await client.createFolder({ name, description?, color? });
await client.updateFolder({ folderId, name?, description? });
await client.deleteFolder(folderId); // soft delete (archive)
await client.archiveFolder(folderId); // same as deleteFolder
await client.destroyFolder(folderId); // permanent delete (must be archived first)Domains
await client.listDomains();
await client.createDomain({ hostname });
await client.updateDomain({ domainId, isPrimary? });
await client.deleteDomain(domainId);
await client.verifyDomain(domainId);Analytics
const analytics = await client.getAnalytics({ qrCodeId?, startDate?, endDate?, granularity? });
const csv = await client.exportAnalyticsCsv({ startDate?, endDate? });Bulk jobs
const job = await client.createQrCodesBulk(rows);
const status = await client.getBulkJob(jobId);Billing
const wallet = await client.getWallet();
await client.updateAutoTopOff({ autoTopOffEnabled, autoTopOffAmountMicrosUsd });
await client.initiateTopOff();Pricing
Pay-per-use, no monthly fees:
| Action | Cost | |--------|------| | Create short link / dynamic QR | $0.05 | | Click / scan | $0.0005 | | Static QR | Free | | Routing rules, pixels, webhooks | Included in click cost |
License
MIT
