/ api/ v1/ account(getAccount)El plan del usuario y cuánto ha usado de sus límites de artículos y colecciones.
Sin parámetros.
Desarrolladores · API REST
Lee y modifica las colecciones y los artículos de un usuario de Owlect por HTTPS. Cada petición lleva un token de acceso OAuth que el usuario concedió a tu app, y solo ve los datos de ese usuario.
URL base
https://owlect.app/api/v1Registra tu app
Envía por POST tu URI de retorno al endpoint de registro y guarda el client_id que devuelve.
Obtén un token
Envía al usuario a la URL de autorización: inicia sesión con Google y pulsa Permitir. Después cambia el código por un token de acceso.
Llama a la API
Envía Authorization: Bearer <token> en cada petición. Empieza por GET /account.
Owlect es un servidor de autorización OAuth 2.1. Las apps son clientes públicos que se identifican con PKCE, así que no hay ningún secreto que se pueda filtrar.
Las URI de retorno deben ser https, o http en localhost. El registro es abierto y tiene límite de frecuencia.
curl -X POST https://owlect.app/api/oauth/register \
-H "Content-Type: application/json" \
-d '{"client_name": "My app", "redirect_uris": ["https://myapp.example/callback"]}'Usa response_type=code, un code_challenge PKCE S256, tu redirect_uri, un valor de state y scope="read create update delete" (pide solo lo que necesites). El usuario inicia sesión con Google, ve una pantalla de consentimiento con la dirección de tu app y marca qué permitir: lectura y creación vienen seleccionadas. El campo scope de la respuesta del token indica lo concedido.
https://owlect.app/oauth/authorize?response_type=code
&client_id=CLIENT_ID
&redirect_uri=https%3A%2F%2Fmyapp.example%2Fcallback
&code_challenge=CODE_CHALLENGE&code_challenge_method=S256
&scope=read%20create%20update%20delete&state=STATEEnvía por POST el código y tu code_verifier al endpoint de tokens. Recibes un token de acceso (1 hora) y un token de actualización (30 días) que rota en cada uso: guarda siempre el más reciente.
curl -X POST https://owlect.app/api/oauth/token \
-d grant_type=authorization_code \
-d code=CODE -d client_id=CLIENT_ID \
-d redirect_uri=https://myapp.example/callback \
-d code_verifier=CODE_VERIFIEREnvía Authorization: Bearer <access_token>. Cuando caduque, usa grant_type=refresh_token para obtener un par nuevo.
curl -X POST https://owlect.app/api/oauth/token \
-d grant_type=refresh_token \
-d refresh_token=REFRESH_TOKEN -d client_id=CLIENT_IDreadVer tus colecciones y artículos. Siempre activado.
createAñadir colecciones y artículos. Activado por defecto.
updateCambiar colecciones y artículos. Desactivado salvo que lo marques.
deleteEliminar colecciones y artículos. Desactivado salvo que lo marques.
Todavía no hay claves de API personales: cada token nace de un usuario que aprueba tu app, y el usuario puede revocarlo cuando quiera en Ajustes -> Apps conectadas.
Todos los endpoints reciben y devuelven JSON. Los ids son UUID.
/ api/ v1/ account(getAccount)El plan del usuario y cuánto ha usado de sus límites de artículos y colecciones.
Sin parámetros.
/ api/ v1/ collections(listCollections)Todas las colecciones del usuario, primero las modificadas más recientemente.
Sin parámetros.
/ api/ v1/ collections(createCollection)Crea una colección. Los tipos integrados reciben sus campos estándar si no envías fieldDefinitions. El tipo personalizado (custom) requiere Owlect Plus.
namecuerpoObligatorio
string, 1-100
Nombre de la colección.
typecuerpoObligatorio
dolls | board_games | coins | stamps | music | pokemon_cards | sneakers | retro_games | funko_pop | lego | comic_books | books | watches | cars | hot_wheels | custom
Tipo de colección. Define los campos por defecto y las búsquedas que usa la app.
descriptioncuerpo
string, max 500
Se muestra en la página de la colección.
fieldDefinitionscuerpo
array of { key, label, type, options?, required? }
Campos personalizados. Omítelo para usar los campos estándar del tipo.
/ api/ v1/ collections/ {collectionId}(getCollection)Una colección con las definiciones de sus campos personalizados. Léelas antes de escribir customFieldValues.
collectionIdrutaObligatorio
uuid
Id de una de las colecciones del usuario (de la lista de colecciones).
/ api/ v1/ collections/ {collectionId}(updateCollection)Cambia el nombre, la descripción o las definiciones de campos. Lo que no envíes se queda igual.
collectionIdrutaObligatorio
uuid
Colección que se cambia.
namecuerpo
string, 1-100
Nuevo nombre.
descriptioncuerpo
string, max 500
Nueva descripción.
fieldDefinitionscuerpo
array of { key, label, type, options?, required? }
Sustituye toda la lista de campos.
/ api/ v1/ collections/ {collectionId}(deleteCollection)Elimina la colección y todos sus artículos. confirmName debe coincidir exactamente con el nombre de la colección.
collectionIdrutaObligatorio
uuid
Colección que se elimina.
confirmNameconsultaObligatorio
string (the collection's exact name)
Debe coincidir exactamente con el nombre de la colección.
/ api/ v1/ collections/ {collectionId}/ items(searchItems)Artículos de una colección, primero los más nuevos, con búsqueda opcional por nombre y filtro de venta. Paginado con cursor.
collectionIdrutaObligatorio
uuid
Colección en la que buscar.
queryconsulta
string, max 200
Coincidencia con el nombre del artículo, sin distinguir mayúsculas.
forSaleconsulta
boolean
true para artículos a la venta, false para el resto.
limitconsulta
integer 1-50, default 20
Artículos por página.
cursorconsulta
string (nextCursor from the previous page)
nextCursor de la página anterior. Omítelo en la primera página.
/ api/ v1/ collections/ {collectionId}/ items(createItems)Añade hasta 50 artículos en una petición. Los valores de campos personalizados se validan antes; si algún artículo no es válido, no se guarda nada.
collectionIdrutaObligatorio
uuid
Colección a la que se añade.
itemscuerpoObligatorio
array, 1-50 items
Los artículos que se crean.
items[].namecuerpoObligatorio
string, 1-200
Nombre del artículo.
items[].descriptioncuerpo
string, max 1000
Notas en texto libre.
items[].quantitycuerpo
integer 1-999
Cuántos ejemplares tienes.
items[].customFieldValuescuerpo
object: field key -> string | number | boolean | null
Valores por clave de los campos de la colección (lee primero la colección para conocerlas). Las claves desconocidas se rechazan con la lista de las válidas.
items[].forSalecuerpo
boolean
Pone el artículo a la venta.
items[].salePricecuerpo
integer (whole currency units) | null
Precio en unidades enteras, p. ej. 40 para 40 $.
items[].saleCurrencycuerpo
currency code, e.g. USD, EUR, UAH
Moneda del precio. Por defecto USD.
items[].completenesscuerpo
complete | incomplete | partial | sealed | unknown | null
Si el artículo está completo, precintado, etc.
items[].barcodecuerpo
string, max 64 | null
EAN, UPC o ISBN.
items[].coverUrlcuerpo
https URL | null
Enlace a una imagen de portada. Se guarda como enlace, no se sube.
/ api/ v1/ collections/ {collectionId}/ items(deleteItems)Elimina hasta 25 artículos de la colección.
collectionIdrutaObligatorio
uuid
Colección a la que pertenecen los artículos.
idsconsultaObligatorio
comma-separated uuids
Ids de los artículos que se eliminan, separados por comas.
/ api/ v1/ items/ {itemId}(getItem)Un artículo con todos sus campos.
itemIdrutaObligatorio
uuid
Id de un artículo (de la lista o la búsqueda de una colección).
/ api/ v1/ items/ {itemId}(updateItem)Cambia solo los campos que envías. customFieldValues se combina por clave y null borra un campo.
itemIdrutaObligatorio
uuid
Artículo que se cambia.
namecuerpo
string, 1-200
Nuevo nombre.
descriptioncuerpo
string, max 1000
Notas en texto libre.
quantitycuerpo
integer 1-999
Cuántos ejemplares tienes.
customFieldValuescuerpo
object: field key -> string | number | boolean | null
Valores por clave de los campos de la colección (lee primero la colección para conocerlas). Las claves desconocidas se rechazan con la lista de las válidas.
forSalecuerpo
boolean
Pone el artículo a la venta.
salePricecuerpo
integer (whole currency units) | null
Precio en unidades enteras, p. ej. 40 para 40 $.
saleCurrencycuerpo
currency code, e.g. USD, EUR, UAH
Moneda del precio. Por defecto USD.
completenesscuerpo
complete | incomplete | partial | sealed | unknown | null
Si el artículo está completo, precintado, etc.
barcodecuerpo
string, max 64 | null
EAN, UPC o ISBN.
coverUrlcuerpo
https URL | null
Enlace a una imagen de portada. Se guarda como enlace, no se sube.
Sustituye $TOKEN por un token de acceso y los ids por ids reales.
curl https://owlect.app/api/v1/collections \
-H "Authorization: Bearer $TOKEN"curl -X POST https://owlect.app/api/v1/collections/COLLECTION_ID/items \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"items": [
{"name": "Wingspan", "customFieldValues": {"game_type": "Base Game"}},
{"name": "Scythe", "quantity": 2}
]}'curl "https://owlect.app/api/v1/collections/COLLECTION_ID/items?forSale=true&limit=20" \
-H "Authorization: Bearer $TOKEN"curl -X PATCH https://owlect.app/api/v1/items/ITEM_ID \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"forSale": true, "salePrice": 40, "saleCurrency": "USD"}'Los errores tienen un formato JSON único y un estado HTTP significativo. `code` es estable; `message` es para personas y puede cambiar.
{
"error": {
"code": "invalid_input",
"message": "Unknown field \"publsher\". This collection's fields are: ...",
"details": {
"validKeys": [
"publisher",
"players"
]
}
}
}GET /collections/{collectionId}/items devuelve { items, nextCursor }. Envía nextCursor como ?cursor= para la página siguiente; en la última página es null. Las páginas son estables aunque escribas mientras paginas.
Los límites se aplican por app conectada (concesión). La API REST y el servidor MCP los comparten.
Un Custom GPT puede usar la API de Owlect como acción (Action).
Especificación OpenAPI
https://owlect.app/api/v1/openapi.jsonLas acciones de GPT usan un secreto de cliente, que Owlect emite para cada GPT bajo petición. Escribe a support@owlect.app con la callback URL de tu GPT.
Esta es la v1. Añadir endpoints, parámetros opcionales o campos de respuesta no rompe a los clientes; lo que pueda romper un cliente irá en una versión nueva, con aviso.