URL base: https://www.getly.store. Todos los precios están en centavos (p. ej., 1999 = $19.99).
GET/api/v1/productsread:products
Lista los productos de tu tienda
curl -X GET "https://www.getly.store/api/v1/products?page=1&limit=20" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": [
{
"id": "uuid",
"name": "Premium Icon Pack",
"slug": "premium-icon-pack-abc123",
"price": 1999,
"status": "active",
"category": { "id": "uuid", "name": "Design", "slug": "design" },
"images": [{ "url": "...", "altText": "..." }]
}
],
"total": 42,
"page": 1,
"limit": 20,
"hasMore": true
}
POST/api/v1/productswrite:products
Crea un producto nuevo en tu tienda
curl -X POST "https://www.getly.store/api/v1/products" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "My New Product",
"description": "A great digital product",
"price": 29.99,
"categoryId": "uuid",
"status": "active",
"tags": ["design", "icons"],
"images": [{ "url": "https://cdn.getly.store/...png", "altText": "cover" }],
"files": [{ "fileUrl": "https://cdn.getly.store/files/.../abc.zip", "fileName": "pack.zip", "fileSize": 10485760, "fileType": "application/zip" }]
}'
Respuesta · application/json
{
"success": true,
"data": {
"id": "uuid",
"name": "My New Product",
"slug": "my-new-product-abc123",
"price": 2999,
"status": "active",
"createdAt": "2025-01-15T10:30:00Z"
}
}
GET/api/v1/products/:idread:products
Obtén los detalles de un producto por ID
curl -X GET "https://www.getly.store/api/v1/products/{id}" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": {
"id": "uuid",
"name": "Premium Icon Pack",
"price": 1999,
"images": [...],
"files": [...],
"reviews": [...]
}
}
PATCH/api/v1/products/:idwrite:products
Actualiza un producto existente
curl -X PATCH "https://www.getly.store/api/v1/products/{id}" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Updated Name", "price": 39.99 }'
Respuesta · application/json
{
"success": true,
"data": { "id": "uuid", "name": "Updated Name", "price": 3999 }
}
DELETE/api/v1/products/:idwrite:products
Archiva (borrado lógico) un producto. Deja de aparecer públicamente; los pedidos y las descargas existentes siguen funcionando.
curl -X DELETE "https://www.getly.store/api/v1/products/{id}" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": { "id": "uuid", "status": "archived" },
"message": "Product archived"
}
POST/api/v1/products/:id/fileswrite:products
Adjunta un archivo descargable a un producto. Usa multipart para archivos pequeños, o la subruta presign + un PUT directo a R2 para archivos de hasta 2 GB. También puedes pasar un array files[] a POST /api/v1/products para adjuntarlos al crear el producto.
# Direct upload (multipart) - best for files under ~4MB:
curl -X POST "https://www.getly.store/api/v1/products/{id}/files" \
-H "Authorization: Bearer gk_your_api_key" \
-F "file=@/path/to/your-file.zip"
# Large files (up to 2GB) - 3 steps:
# 1) get a presigned upload URL
curl -X POST "https://www.getly.store/api/v1/products/{id}/files/presign" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "fileName": "pack.zip", "fileSize": 524288000, "fileType": "application/zip" }'
# 2) PUT the bytes straight to R2 (use the returned uploadUrl)
curl -X PUT "<uploadUrl>" --data-binary "@/path/to/pack.zip" \
-H "Content-Length: 524288000"
# 3) attach the uploaded object (use the returned fileUrl)
curl -X POST "https://www.getly.store/api/v1/products/{id}/files" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "fileUrl": "<fileUrl>", "fileName": "pack.zip", "fileSize": 524288000, "fileType": "application/zip" }'
Respuesta · application/json
{
"success": true,
"data": {
"id": "uuid",
"fileName": "pack.zip",
"fileUrl": "https://cdn.getly.store/files/.../abc.zip",
"fileSize": 524288000,
"fileType": "application/zip",
"version": "1.0",
"isLatest": true,
"createdAt": "2026-06-02T10:30:00Z"
}
}
POST/api/v1/uploads/images/presignwrite:products
Obtén una URL prefirmada para subir la imagen de un producto (máx. 10 MB; png, jpeg, webp, gif, avif). Obligatoria antes de que un producto pueda publicarse.
# Images are uploaded in 3 steps - there is no direct multipart route.
# 1) ask for a presigned URL (max 10MB; png, jpeg, webp, gif or avif)
curl -X POST "https://www.getly.store/api/v1/uploads/images/presign" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "fileName": "cover.png", "fileSize": 184320, "contentType": "image/png" }'
# 2) PUT the raw bytes to the returned uploadUrl (expires in 1h) with the
# returned uploadHeaders. Content-Length MUST equal the fileSize you declared.
# Send Content-Type equal to the declared type (curl --data-binary alone sends
# a form type; Getly corrects it when the image is attached, but send it anyway).
curl -X PUT "<uploadUrl>" --data-binary "@/path/to/cover.png" \
-H "Content-Type: image/png" -H "Content-Length: 184320"
# 3) reference the returned publicUrl when you create or update the product.
# An image is REQUIRED before a product can go live.
curl -X PATCH "https://www.getly.store/api/v1/products/{id}" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "images": ["<publicUrl>"] }'
Respuesta · application/json
{
"success": true,
"data": {
"uploadUrl": "https://<bucket>.r2.cloudflarestorage.com/...",
"uploadHeaders": { "Content-Type": "image/png" },
"publicUrl": "https://cdn.getly.store/images/.../abc.png",
"expiresIn": 3600
}
}
GET/api/v1/products/:id/keysread:products
Lista el pool de claves de licencia de un producto: contadores (disponibles/emitidas/en espera) y una lista paginada y enmascarada. La clave en texto plano nunca se devuelve.
curl -X GET "https://www.getly.store/api/v1/products/{id}/keys?limit=50&offset=0" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": {
"keyPoolEnabled": true,
"keyPoolLowThreshold": 5,
"counts": { "available": 12, "issued": 40, "waiting": 0 },
"keys": [
{ "id": "uuid", "masked": "ABCD…WXYZ", "status": "available", "issuedAt": null, "orderItemId": null, "refunded": false }
],
"limit": 50,
"offset": 0,
"total": 52
}
}
POST/api/v1/products/:id/keyswrite:products
Pega tus propias claves, vales o URL únicas en el pool de un producto, una por elemento del array. Los duplicados y los vacíos se informan, no se descartan en silencio; los compradores que estaban esperando reciben una clave de inmediato.
curl -X POST "https://www.getly.store/api/v1/products/{id}/keys" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "keys": ["ABCD-1234-EFGH-5678", "IJKL-9012-MNOP-3456"] }'
Respuesta · application/json
{
"success": true,
"data": {
"added": 2,
"duplicates": 0,
"duplicatesInInput": 0,
"tooLong": 0,
"blank": 0,
"filled": 1
}
}
DELETE/api/v1/products/:id/keys/:keyIdwrite:products
Elimina una clave sin vender del pool. Una clave emitida es un registro de venta y no se puede eliminar: 409 key_not_available.
curl -X DELETE "https://www.getly.store/api/v1/products/{id}/keys/{keyId}" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": { "id": "uuid", "removed": true }
}
GET/api/v1/ordersread:orders
Lista los pedidos que incluyen artículos de tu tienda
curl -X GET "https://www.getly.store/api/v1/orders?page=1&limit=20" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": [
{
"id": "uuid",
"orderId": "uuid",
"price": 2999,
"order": { "status": "completed", "buyer": { "name": "John" } },
"product": { "name": "Premium Pack" }
}
],
"total": 156,
"page": 1
}
GET/api/v1/orders/:idread:orders
Obtén los detalles de un pedido (solo los artículos de tu tienda)
curl -X GET "https://www.getly.store/api/v1/orders/{id}" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": {
"id": "uuid",
"status": "completed",
"total": 5999,
"buyer": { "name": "John", "email": "[email protected]" },
"items": [...]
}
}
GET/api/v1/storeread:store
Obtén la información de tu tienda
curl -X GET "https://www.getly.store/api/v1/store" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": {
"id": "uuid",
"name": "My Store",
"slug": "my-store",
"description": "...",
"totalSales": 250,
"totalRevenue": 450000,
"badges": [...]
}
}
PATCH/api/v1/storewrite:store
Actualiza el nombre de la tienda, la descripción, el sitio web y socialLinks
curl -X PATCH "https://www.getly.store/api/v1/store" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "description": "Updated store description" }'
Respuesta · application/json
{
"success": true,
"data": { "id": "uuid", "name": "My Store", "description": "Updated store description" }
}
GET/api/v1/analyticsread:analytics
Obtén las analíticas de ventas de tu tienda
curl -X GET "https://www.getly.store/api/v1/analytics" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": {
"totalSales": 250,
"totalRevenue": 450000,
"monthlySales": 42,
"monthlyRevenue": 75000,
"averageOrderValue": 1800,
"productCount": 15,
"totalDownloads": 1200,
"salesByMonth": [
{ "month": "2025-01", "sales": 38, "revenue": 68000 }
]
}
}
GET/api/v1/webhook-endpointswebhooks:manage
Lista los endpoints de webhook de tu tienda
curl -X GET "https://www.getly.store/api/v1/webhook-endpoints" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": {
"items": [
{
"id": "uuid",
"url": "https://example.com/webhooks",
"events": ["sale.completed"],
"isActive": true
}
],
"nextCursor": null
}
}
POST/api/v1/webhook-endpointswebhooks:manage
Registra un nuevo endpoint de webhook
curl -X POST "https://www.getly.store/api/v1/webhook-endpoints" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks",
"events": ["sale.completed", "product.updated"]
}'
Respuesta · application/json
{
"success": true,
"data": {
"id": "uuid",
"url": "https://example.com/webhooks",
"events": ["sale.completed", "product.updated"],
"secret": "abcdef1234567890..."
}
}
POST/api/v1/postswrite:posts
Crea una entrada del blog de creador a partir de Markdown. Pon crosspostMuhamor en true para mostrarla también en la comunidad Getly Creators de Muhamor: la copia enlaza a tu entrada como original, y una entrada solo para suscriptores se publica allí únicamente como adelanto.
curl -X POST "https://www.getly.store/api/v1/posts" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7b1f0c2e-post-1" \
-d '{
"title": "How I made my icon pack",
"contentMarkdown": "## The idea\n\nIt started with...",
"status": "published",
"crosspostMuhamor": true
}'
Respuesta · application/json
{
"success": true,
"data": {
"id": "uuid",
"title": "How I made my icon pack",
"slug": "how-i-made-my-icon-pack",
"status": "published",
"crosspostMuhamor": true
}
}
GET/api/v1/public/products/{slug}public
Público, sin clave de API: la ficha de un producto activo por su slug (nombre, precio en centavos con cualquier oferta vigente, imagen de portada, tienda). 404 para todo lo que no esté a la venta. 60 solicitudes por minuto por IP.
curl "https://www.getly.store/api/v1/public/products/premium-icon-pack-abc123"
Respuesta · application/json
{
"success": true,
"data": {
"slug": "premium-icon-pack-abc123",
"name": "Premium Icon Pack",
"shortDescription": "120 line icons",
"priceCents": 1999,
"currency": "USD",
"avgRating": 4.8,
"reviewCount": 12,
"imageUrl": "https://cdn.getly.store/images/.../cover.webp",
"store": { "name": "Pixel Studio", "slug": "pixel-studio" },
"urls": { "product": "https://www.getly.store/product/premium-icon-pack-abc123" }
}
}
POST/api/v1/billing/planswrite:billing
Crea un plan recurrente para tu PROPIO producto (Getly Billing). amount en centavos enteros (mín. 50), intervalUnit day/week/month/year, intervalCount 1–52. Requiere una solicitud de Billing aprobada: 403 billing_not_approved hasta entonces. GET lista los planes; GET/PATCH /{id} lee y edita uno.
curl -X POST "https://www.getly.store/api/v1/billing/plans" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Pro", "amount": 1900, "intervalUnit": "month", "externalId": "pro-monthly" }'
Respuesta · application/json
{
"success": true,
"data": {
"id": "uuid",
"name": "Pro",
"amount": 1900,
"currency": "usd",
"interval": { "unit": "month", "count": 1 },
"externalId": "pro-monthly",
"isActive": true
}
}
POST/api/v1/billing/checkoutwrite:billing
Genera una página de suscripción alojada para un cliente, válida 24 horas. customerRef es tu propio id del cliente y vuelve en cada webhook billing.* como externalCustomerRef. El cliente paga con tarjeta (se renueva solo) o con cripto (un periodo cada vez).
curl -X POST "https://www.getly.store/api/v1/billing/checkout" \
-H "Authorization: Bearer gk_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "planId": "uuid", "customerRef": "user_8841",
"successUrl": "https://your-app.com/welcome",
"cancelUrl": "https://your-app.com/pricing" }'
Respuesta · application/json
{
"success": true,
"data": {
"url": "https://www.getly.store/billing/subscribe/uuid?t=…",
"expiresAt": "2026-09-09T09:00:00.000Z"
}
}
GET/api/v1/billing/subscriptions/{id}read:billing
La comprobación de estado que hace tu backend antes de dar acceso. status: active, past_due (falló la renovación con tarjeta, el procesador reintenta), canceled, expired (se acabó el periodo pagado con cripto). Trata active y past_due como con derecho de acceso hasta currentPeriodEnd. El endpoint de lista filtra por status, customerRef y planId.
curl "https://www.getly.store/api/v1/billing/subscriptions/uuid" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": {
"id": "uuid",
"customerRef": "user_8841",
"status": "active",
"paymentMethod": "stripe",
"currentPeriodEnd": "2026-10-08T09:14:00.000Z",
"cancelAtPeriodEnd": false,
"plan": { "name": "Pro", "amount": 1900, "interval": { "unit": "month", "count": 1 } }
}
}
POST/api/v1/billing/subscriptions/{id}/cancelwrite:billing
Detiene la renovación al final del periodo pagado, nunca un corte inmediato. Recibes billing.subscription.canceled cuando termina (tarjeta) o billing.subscription.expired (cripto). 409 subscription_not_cancellable si ya terminó.
curl -X POST "https://www.getly.store/api/v1/billing/subscriptions/uuid/cancel" \
-H "Authorization: Bearer gk_your_api_key"
Respuesta · application/json
{
"success": true,
"data": { "id": "uuid", "status": "active", "cancelAtPeriodEnd": true, "currentPeriodEnd": "2026-10-08T09:14:00.000Z" }
}