Documentación de la API

Integra tus aplicaciones con el marketplace: lee tu cuenta y artículos, obtén tus ventas para paneles de control personalizados y verifica los códigos de compra del comprador desde tu propio servidor de licencias.

URL base: https://sellmycode.net/api Formato: JSON Límite de peticiones: 60 req/min
Comprobación rápida
curl https://sellmycode.net/api

Autenticación

Cada solicitud necesita un token de acceso personal. Crea tokens con nombre y ámbito en tu espacio de trabajo en Configuración → Clave API — cada aplicación obtiene su propio token con solo los permisos que necesita, y puedes revocar cualquiera de ellos en cualquier momento.

account:read items:read sales:read purchases:validate purchases:read balance:read catalog:read
Envía la clave en el encabezado de autorización (recomendado). El parámetro de consulta api_key también se acepta para la compatibilidad con versiones anteriores, pero las claves en las URL pueden filtrarse en los registros.
Recomendado — Authorization header
curl https://sellmycode.net/api/account/details \
  -H "Authorization: Bearer YOUR_API_KEY"
Alternativa — X-Api-Key header
curl https://sellmycode.net/api/account/details \
  -H "X-Api-Key: YOUR_API_KEY"

Errores y límites

CódigoSignificado
200éxito
400Error de validación: falta un parámetro requerido o está mal formado
401Clave API inválida o faltante
404Recurso no encontrado (también se devuelve para un código de compra no válido)
429Límite de peticiones excedido: espera y vuelve a intentarlo (60 peticiones por minuto)
Forma del error
{
  "status": "error",
  "msg": "Invalid request"
}

GETDetalles de la cuenta

Devuelve el perfil de la cuenta propietaria de la clave API.

GET/api/account/details
Request
curl https://sellmycode.net/api/account/details \
  -H "Authorization: Bearer YOUR_API_KEY"

GETTodos los artículos

Todos tus artículos aprobados, los más recientes primero. Solo autores.

GET/api/items/all
Request
curl https://sellmycode.net/api/items/all \
  -H "Authorization: Bearer YOUR_API_KEY"

GETArtículo individual

Uno de tus artículos aprobados por su ID numérico.

GET/api/items/item?item_id={id}
ParámetroTipoDescripción
item_id RequeridointegerEl ID del artículo (mostrado en la lista de artículos de tu espacio de trabajo)
Request
curl "https://sellmycode.net/api/items/item?item_id=123" \
  -H "Authorization: Bearer YOUR_API_KEY"

GETVentas

Tus ventas, las más recientes primero: crea paneles de ingresos o sincroniza pedidos con tus propias herramientas. Paginado.

GET/api/sales
ParámetroTipoDescripción
from opcionaldateY-m-d — solo ventas en o después de esta fecha
to opcionaldateY-m-d — solo ventas en o antes de esta fecha
item_id opcionalintegerfiltrar por uno de tus artículos
status opcionalstringactive | refunded | cancelled | held
per_page opcionalintegerpor defecto 25, máximo 50
page opcionalintegernúmero de página
Request
curl "https://sellmycode.net/api/sales?from=2026-01-01&status=active&per_page=25" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response 200
{
  "status": "success",
  "pagination": { "page": 1, "per_page": 25, "total": 132, "last_page": 6 },
  "sales": [
    {
      "id": 981,
      "purchase_code": "8f14e45f-ce95-41d8-a2b6-72e5f13d81a7",
      "item": { "id": 123, "name": "My Theme" },
      "buyer": "johndoe",
      "license_type": "Regular",
      "price": 29.0,
      "fee": 5.8,
      "earning": 23.2,
      "currency": "USD",
      "sale_status": "active",
      "cleared": true,
      "date": "2026-07-01T09:30:00+00:00"
    }
  ]
}

GETMis compras

Tus propias compras como comprador, las más recientes primero: consulta licencias y ventanas de descarga desde tus herramientas. Paginado.

GET/api/purchases
ParámetroTipoDescripción
status opcionalstringactive | refunded | cancelled | held
per_page opcionalintegerpor defecto 25, máximo 50
page opcionalintegernúmero de página
Request
curl "https://sellmycode.net/api/purchases?status=active" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response 200
{
  "status": "success",
  "pagination": { "page": 1, "per_page": 25, "total": 3, "last_page": 1 },
  "purchases": [
    {
      "purchase_code": "8f14e45f-ce95-41d8-a2b6-72e5f13d81a7",
      "item": { "id": 123, "name": "My Theme", "url": "https://sellmycode.net/item/my-theme/123" },
      "license_type": "Regular",
      "price": 29.0,
      "currency": "USD",
      "purchase_status": "active",
      "download_expiry_at": "2027-01-01T00:00:00+00:00",
      "download_expired": false,
      "date": "2026-07-01T09:30:00+00:00"
    }
  ]
}

GETSaldo

Una instantánea de solo lectura de tus monederos: ganancias retirables, ganancias aún en período de compensación y Crédito de la tienda. Opcionalmente, incluye tu historial de extractos.

GET/api/balance
ParámetroTipoDescripción
statements opcionalboolean1 para incluir extractos recientes
wallet opcionalstringbalance | store_credit — filtrar extractos por monedero
per_page opcionalintegerpor defecto 25, máximo 50
Request
curl "https://sellmycode.net/api/balance?statements=1&wallet=balance" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response 200
{
  "status": "success",
  "currency": "USD",
  "wallets": {
    "balance": 1250.75,
    "pending_balance": 89.4,
    "store_credit": 12.5
  },
  "pagination": { "page": 1, "per_page": 25, "total": 57, "last_page": 3 },
  "statements": [
    {
      "id": 4021,
      "title": "[Sale] #981 (My Theme)",
      "wallet": "balance",
      "type": "credit",
      "amount": 29.0,
      "total": 23.2,
      "date": "2026-07-01T09:30:05+00:00"
    }
  ]
}

POSTValidación de compra

Verifica un código de compra que te da un comprador, el núcleo de cualquier sistema de licencias. Devuelve los detalles de la compra cuando el código pertenece a UNO de TUS artículos y aún está activo; de lo contrario, 404.

POST/api/purchases/validation
ParámetroTipoDescripción
purchase_code RequeridostringEl código del comprador (mostrado en su página de compras y certificado de licencia)
curl -X POST https://sellmycode.net/api/purchases/validation \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d "purchase_code=BUYER_PURCHASE_CODE"
// license check from your app / plugin
$ch = curl_init('https://sellmycode.net/api/purchases/validation');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY'],
    CURLOPT_POSTFIELDS => http_build_query(['purchase_code' => $code]),
]);
$res = json_decode(curl_exec($ch), true);
$valid = ($res['status'] ?? '') === 'success';
// Node.js 18+ (built-in fetch)
const res = await fetch('https://sellmycode.net/api/purchases/validation', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ purchase_code: code }),
});
const data = await res.json();
const valid = res.ok && data.status === 'success';
# Python 3 + requests
import requests

res = requests.post(
    'https://sellmycode.net/api/purchases/validation',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    data={'purchase_code': code},
    timeout=10,
)
valid = res.status_code == 200 and res.json().get('status') == 'success'
Response 200
{
  "status": "success",
  "buyer": "johndoe",
  "item": {
    "purchase_code": "8f14e45f-ce95-41d8-a2b6-72e5f13d81a7",
    "license_type": "Regular",
    "price": 29.0,
    "currency": "USD",
    "item": { "…item fields…" },
    "supported_until": "2026-12-01T00:00:00+00:00",
    "download_expiry": "2026-08-01T00:00:00+00:00",
    "downloaded": true,
    "date": "2026-07-01T09:30:00+00:00"
  }
}
Se devuelve un 404 TANTO para un código desconocido como para una compra reembolsada/bloqueada; trata cualquier no-200 como "licencia no válida".

GETCatálogo Público

Navega y busca en todo el catálogo aprobado — abierto a TODAS las cuentas, comprador o autor. Construye rastreadores de precios, exhibiciones de portafolios o paneles de categorías. Devuelve solo datos de la tienda: precios orientados al comprador (descuentos incluidos), valoraciones y recuentos de ventas — nunca archivos, enlaces de descarga o identidades de compradores.

GET/api/catalog/items
ParámetroTipoDescripción
search opcionalstringbúsqueda de texto completo en nombres de artículos y etiquetas
category opcionalstringun slug de categoría (ver el endpoint de categorías)
sort opcionalstringlatest (predeterminado) | popular | rating
per_page opcionalintegerpor defecto 25, máximo 50
page opcionalintegernúmero de página
Request
curl "https://sellmycode.net/api/catalog/items?search=woocommerce&sort=popular" \
  -H "Authorization: Bearer YOUR_API_KEY"
Response 200
{
  "status": "success",
  "pagination": { "page": 1, "per_page": 25, "total": 64, "last_page": 3 },
  "items": [
    {
      "id": 123,
      "name": "My Theme",
      "url": "https://sellmycode.net/item/my-theme/123",
      "thumbnail": "https://sellmycode.net/files/thumbnails/…",
      "category": { "id": 4, "name": "WordPress", "slug": "wordpress" },
      "author": "janedoe",
      "price": { "regular": 29.0, "extended": 145.0 },
      "currency": "USD",
      "rating": { "average": 4.8, "count": 36 },
      "version": "2.1.0",
      "updated_at": "2026-07-10T08:00:00+00:00",
      "published_at": "2026-01-05T12:00:00+00:00"
    }
  ]
}
GET/api/catalog/items/{id}

Detalle público completo de un artículo aprobado — los campos de la lista más descripción, vistas previas de medios, lista de archivos incluidos y marco.

Request
curl https://sellmycode.net/api/catalog/items/123 \
  -H "Authorization: Bearer YOUR_API_KEY"
GET/api/catalog/categories

Todas las categorías con sus recuentos de artículos aprobados — usa el slug como filtro de categoría anterior.

Response 200
{
  "status": "success",
  "categories": [
    { "id": 4, "name": "WordPress", "slug": "wordpress", "url": "https://sellmycode.net/categories/wordpress", "items_count": 128 }
  ]
}
Cualquier cuenta registrada puede crear un token con el permiso catalog:read — no necesitas ser autor ni haber realizado una compra.

Activación de licencia

Para software que se conecta con el servidor: scripts PHP, aplicaciones de escritorio o móviles. Su instalación envía el código de compra y su dominio; nosotros confirmamos la licencia y contamos en cuántos sitios se ejecuta, para que no tenga que alojar un servidor de licencias usted mismo.

Estos tres endpoints NO necesitan ningún token de API: el código de compra es la credencial, por lo que el código que envía a los compradores puede llamarlos directamente. Están limitados a 60 llamadas cada 10 minutos por IP.
El derecho a USAR el software nunca expira. Cuando el soporte de actualizaciones finaliza, verify sigue devolviendo válido; solo el bloque de actualizaciones informa que debe renovarse. Un periodo de actualización expirado nunca debe romper un sitio en vivo.
POST/api/license/activate
POST/api/license/verify
POST/api/license/deactivate
ParámetroTipoDescripción
purchase_codestringel código que recibió el comprador
domainstringel sitio que ejecuta el software; el esquema, www y la ruta se eliminan automáticamente
Request
curl "https://sellmycode.net/api/license/activate" \
  -H "Content-Type: application/json" \
  -d '{"purchase_code":"d71c21a3-...","domain":"customer-site.com"}'
Response 200
{
  "status": "success",
  "code": "activated",
  "domain": "customer-site.com",
  "license_type": "Regular",
  "activation_limit": 2,
  "activations_used": 1,
  "updates": { "active": true, "until": "2027-01-30T10:00:00+00:00" }
}
Código de errorHTTPSignificado
invalid_code403código de compra desconocido, reembolsado o cancelado
activation_limit_reached403todos los sitios permitidos están en uso; desactive uno primero
not_activated403este dominio nunca se ha activado (o ha sido liberado)
invalid_domain400no se pudo analizar el dominio
rate_limited429demasiadas llamadas desde esta IP
Establece el número de sitios permitidos por licencia cuando publiques el artículo (Límite de activación, por separado para Regular y Extendida). Déjalo en blanco para ilimitado. Los compradores liberan sus propios sitios en Área de trabajo → Licencias, y puedes revocar uno desde la misma página.

Actualizaciones del artículo (Toolkit)

Permita que un sitio de WordPress mantenga actualizados los temas y plugins que compró aquí. Indíquenos qué paquetes están instalados, reciba los que tienen una versión más reciente y luego obtenga el ZIP instalable. Esto es lo que usa el plugin SellMyCode Toolkit; solo necesita estos endpoints si está creando su propio actualizador.

Requiere un token con el permiso updates:read. Las actualizaciones se ofrecen mientras el periodo de soporte de actualizaciones de su compra esté activo; una vez finalizado, le seguiremos informando de que existe una versión más reciente, pero el archivo ya no estará disponible hasta que renueve.

¿Usas WordPress? Sáltate el código

El plugin SellMyCode Toolkit ya vincula estos endpoints a las pantallas habituales de actualización de Temas y Plugins. Instálalo, pega un token y los artículos comprados se actualizarán como cualquier otra cosa en WordPress.

POSTBuscar actualizaciones

POST/api/updates/check
ParámetroTipoDescripción
packagesarraypaquetes instalados, hasta 100 por llamada
packages[].slugstringel nombre de la carpeta del tema o plugin
packages[].typestringtheme | plugin
packages[].version opcionalstringla versión instalada actualmente
Request
curl "https://sellmycode.net/api/updates/check" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"packages":[{"slug":"my-theme","type":"theme","version":"1.4.0"}]}'
Response 200
{
  "status": "success",
  "checked": 1,
  "updates": [
    {
      "item_id": 123,
      "slug": "my-theme",
      "type": "theme",
      "name": "My Theme",
      "installed_version": "1.4.0",
      "new_version": "1.6.2",
      "changelog": { "version": "1.6.2", "body": "Fixed ..." },
      "can_download": true,
      "reason": null,
      "update_window_ends_at": "2027-01-30T10:00:00+00:00",
      "download_url": "https://sellmycode.net/api/updates/download/123",
      "renew_url": null
    }
  ]
}
Solo se devuelven los artículos que realmente compró; cualquier otra cosa instalada en el sitio se ignora, por lo que es seguro enviar su lista completa de plugins.

GETDescargar el paquete instalable

GET/api/updates/download/{id}

Responde con una redirección 302 a una URL de almacenamiento de corta duración (válida por unos minutos). Siga las redirecciones y guarde el ZIP: solo contiene el tema o plugin, listo para instalar.

Request
curl -L -o update.zip "https://sellmycode.net/api/updates/download/123" \
  -H "Authorization: Bearer YOUR_API_KEY"
Código de errorHTTPSignificado
not_purchased403esta cuenta no compró el artículo
update_window_expired403el soporte de actualizaciones ha finalizado — renew_url se incluye en la respuesta
no_installable_file404el autor no ha proporcionado un paquete instalable para este artículo
item_removed410el artículo ya no está disponible
Estos endpoints están limitados a 60 solicitudes por minuto. Un sitio normalmente solo necesita unas pocas llamadas al día: compruebe una vez y luego descargue lo que haya cambiado.

Webhooks de venta

En lugar de sondear el endpoint de ventas, registra una URL HTTPS y te enviaremos un evento JSON firmado en el momento en que algo suceda. Administra los endpoints en tu espacio de trabajo en Configuración → Clave de API → Webhooks (hasta 5, cada uno con su propio secreto de firma que se muestra una vez en la creación).

EventoEnviado cuando
sale.createdSe vende uno de tus artículos, paquetes o cursos
sale.refundedUna de tus ventas es reembolsada o cancelada — revoca la licencia de tu lado

Entrega

Cada entrega es un HTTP POST con un cuerpo JSON. Responde con cualquier estado 2xx en 10 segundos; realiza trabajos pesados asincrónicamente. Las entregas fallidas se reintentan 3 veces (después de 1 minuto, 15 minutos y 1 hora). Después de 10 fallos consecutivos — o una respuesta 410 Gone — el endpoint se deshabilita automáticamente y se te notifica.

EncabezadoDescripción
X-SMC-EventEl nombre del evento, p. ej. sale.created
X-SMC-DeliveryID de entrega único (UUID) — desduplica los reintentos con él
X-SMC-Signaturet=<unix>,v1=<hex> — Firma HMAC-SHA256 (ver abajo)
Carga útil de ejemplo — sale.created
{
  "id": "1c2f6a7e-9d31-4c3e-8f5b-2d9f8f4f1a10",
  "event": "sale.created",
  "created_at": "2026-07-18T10:30:00+00:00",
  "data": {
    "sale_id": 981,
    "purchase_code": "8f14e45f-ce95-41d8-a2b6-72e5f13d81a7",
    "type": "item",
    "item": { "id": 123, "name": "My Theme" },
    "buyer": "johndoe",
    "license_type": "Regular",
    "price": 29.0,
    "earning": 23.2,
    "currency": "USD",
    "date": "2026-07-18T10:30:00+00:00"
  }
}

Verificando la firma

Calcula HMAC-SHA256 sobre la cadena "timestamp.rawBody" con tu secreto de firma y compáralo (tiempo constante) con el valor v1. Rechaza las entregas cuya marca de tiempo sea anterior a ~5 minutos para evitar repeticiones.

$secret  = 'whsec_...'; // from Settings → API Key → Webhooks
$body    = file_get_contents('php://input');
$header  = $_SERVER['HTTP_X_SMC_SIGNATURE'] ?? '';

parse_str(str_replace(',', '&', $header), $sig); // ['t' => ..., 'v1' => ...]

$expected = hash_hmac('sha256', $sig['t'] . '.' . $body, $secret);

if (!hash_equals($expected, $sig['v1'] ?? '') || abs(time() - (int) $sig['t']) > 300) {
    http_response_code(400); exit;
}

http_response_code(200); // ack fast, process async
// Express: use express.raw() so the RAW body is available for the HMAC
const crypto = require('crypto');
const SECRET = 'whsec_...'; // from Settings → API Key → Webhooks

app.post('/webhooks/sellmycode', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('X-SMC-Signature') || '';
  const sig = Object.fromEntries(header.split(',').map(p => p.split('=')));

  const expected = crypto.createHmac('sha256', SECRET)
    .update(sig.t + '.' + req.body.toString('utf8')).digest('hex');

  const fresh = Math.abs(Date.now() / 1000 - Number(sig.t)) < 300;
  const valid = sig.v1 &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig.v1));

  if (!valid || !fresh) return res.sendStatus(400);

  const event = JSON.parse(req.body); // { id, event, created_at, data }
  res.sendStatus(200); // ack fast, process async
});
# Flask — request.get_data() is the RAW body needed for the HMAC
import hmac, hashlib, time
from flask import Flask, request

SECRET = 'whsec_...'  # from Settings → API Key → Webhooks

@app.route('/webhooks/sellmycode', methods=['POST'])
def webhook():
    header = request.headers.get('X-SMC-Signature', '')
    sig = dict(p.split('=', 1) for p in header.split(',') if '=' in p)

    body = request.get_data()  # bytes, unparsed
    expected = hmac.new(
        SECRET.encode(), (sig.get('t', '') + '.').encode() + body, hashlib.sha256
    ).hexdigest()

    fresh = abs(time.time() - float(sig.get('t', 0))) < 300
    if not (hmac.compare_digest(expected, sig.get('v1', '')) and fresh):
        return '', 400

    event = request.get_json()  # { id, event, created_at, data }
    return '', 200  # ack fast, process async
# Rails / Rack — request.body.read is the RAW body needed for the HMAC
SECRET = 'whsec_...' # from Settings → API Key → Webhooks

def webhook
  header = request.headers['X-SMC-Signature'].to_s
  sig = header.split(',').to_h { |p| p.split('=', 2) }

  body = request.body.read
  expected = OpenSSL::HMAC.hexdigest('SHA256', SECRET, "#{sig['t']}.#{body}")

  fresh = (Time.now.to_i - sig['t'].to_i).abs < 300
  valid = sig['v1'] &&
    ActiveSupport::SecurityUtils.secure_compare(expected, sig['v1'])

  return head :bad_request unless valid && fresh

  event = JSON.parse(body) # { id, event, created_at, data }
  head :ok # ack fast, process async
end
Los endpoints deben ser URLs HTTPS públicas. Las entregas nunca siguen redireccionamientos. Utiliza el ID X-SMC-Delivery para desduplicar — un reintento después de un tiempo de espera puede llegar incluso si ya procesaste el original.