Autenticación y límites de la API de revendedores
Tokens Bearer, scopes, lista de IP permitidas, límite de tasa, códigos de error, idempotencia y paginación de la API de revendedores de OneProvider.
Tokens Bearer, permisos (scopes), lista de IP permitidas, límite de frecuencia, códigos de error, claves de idempotencia y paginación de la API de revendedores.
Todos los modelos, capacidades y precios Índice de la documentación para agentes de IA:https://oneprovider.dev/docs/llms.txt Tokens
Un token tiene la forma rsk_ seguido de 40 caracteres. Créalo en el panel (pestaña de revendedor, «API y ajustes»); el valor se muestra una sola vez, y nosotros guardamos solo un hash y los últimos 4 caracteres. Puedes tener hasta 10 tokens activos y revocar cualquiera en cualquier momento. Al crear un token se le puede dar una vida útil (de 1 a 365 días): pasada esta, el token responde 401 token_expired, y expires_at en GET /me indica cuándo ocurre (null: sin vencimiento).
httpAuthorization: Bearer rsk_... Solo desde el servidor CORS está desactivado. Nunca incluyas un token en el bundle de un navegador ni en una app móvil: llama a la API desde tu backend. Si un revendedor pierde el acceso, todos sus tokens responden 403 reseller_disabled. Permisos (scopes)
Un token lleva un conjunto de permisos. Los permisos son independientes: keys no implica read. GET /me funciona con cualquier token válido. Sin el permiso necesario, la respuesta es 403 forbidden_scope.
| Scope | Qué permite |
|---|---|
read | Lectura: saldo y transacciones, precios, modelos, clientes, claves y su consumo, pedidos, planes, estadísticas, los ajustes de la tienda GET /settings, el registro de acciones GET /audit (todos los GET salvo códigos, webhooks, bots y métodos de pago, y el estado del pago de una recarga). |
keys | Escritura: clientes (incluido el bloqueo), emitir, editar, pausar, recargar, rotar y eliminar claves, POST /orders, los ajustes de la tienda PATCH /settings (determinan cómo se ven las claves emitidas). |
codes | Lotes de códigos y los propios códigos (leer, crear, revocar, canjear). Los códigos son secretos, por eso tienen un permiso aparte. |
plans | Crear, editar y eliminar planes (para leer los planes hace falta read). |
billing | Recargas del saldo de revendedor: POST /balance/topups y el estado del pago. |
webhooks | Gestionar webhooks, enviar una prueba, leer el registro de entregas. |
support | Reservado para futuros endpoints de soporte. |
bot | Leer el estado de los bots y de los métodos de pago: GET /bot y GET /payment-providers (sin tokens en las respuestas). Los bots se conectan solo en el panel. |
El permiso de cada método figura en la referencia .
Lista de IP permitidas
Un token puede limitarse a una lista de direcciones IPv4/IPv6 o rangos CIDR (hasta 20). Una solicitud desde otra dirección recibe 403 ip_not_allowed. La lista se define al crear el token.
Límite de frecuencia
20 solicitudes por segundo por token y 100 por segundo por dirección IP de origen. Al superarlo: 429 rate_limited y un encabezado Retry-After. Espera esa cantidad de segundos y reintenta.
Errores
Todos los errores tienen la misma estructura. El mismo id se envía en el encabezado X-Request-Id: indícalo al soporte.
{
"error": {
"code": "insufficient_balance",
"message": "Not enough free reseller balance for this key.",
"request_id": "req_..."
}
} Decide según error.code, no según el texto del mensaje.
| HTTP | code | Significado |
|---|---|---|
| 400 | invalid | Falta un campo o está fuera de rango. |
| 400 | bad_request | No se pudo interpretar la solicitud. |
| 400 | idempotency_key_required | Falta el encabezado Idempotency-Key en un método que gasta dinero. |
| 400 | invalid_url | La URL del webhook no pasó la validación (solo https, sin direcciones IP literales ni redes privadas). |
| 400 | limit_below_spent | El nuevo límite de la clave es menor que lo que la clave ya ha gastado. |
| 400 | currency_required | POST /balance/topups: el proveedor admite varias monedas, indica currency (las permitidas están en topup_providers). |
| 400 | method_unavailable | POST /balance/topups: no existe ese proveedor en topup_providers (bad_currency, bad_email y email_required responden igual para la moneda y el correo). |
| 401 | unauthorized | El token falta, es desconocido o fue revocado. |
| 401 | token_expired | El token venció (expires_at en GET /me): crea uno nuevo. |
| 403 | forbidden_scope | Al token le falta el permiso (scope) necesario. |
| 403 | ip_not_allowed | La IP de la solicitud no está en la lista de IP permitidas del token. |
| 403 | reseller_disabled | El revendedor perdió el acceso; todos los tokens responden así. |
| 403 | banned | La cuenta está bloqueada. |
| 404 | not_found | El objeto no existe o pertenece a otro revendedor. |
| 404 | key_not_found | La clave no existe. |
| 409 | insufficient_balance | El importe no cabe en Disponible (Free, available_usd), consulta la regla del dinero. |
| 409 | idempotency_key_reused | El mismo Idempotency-Key ya se usó con un cuerpo de solicitud distinto: usa una clave nueva. |
| 409 | fund_first | Recarga primero el saldo de revendedor. |
| 409 | not_activated | El panel de revendedor aún no está activado. |
| 409 | name_taken | Ya existe una clave con este nombre. |
| 409 | key_limit | Se alcanzó el número máximo de claves. |
| 409 | plan_limit | Se alcanzó el límite de planes (20). |
| 409 | customer_limit | Se alcanzó el límite de clientes (10 000). |
| 409 | plan_in_use | El plan no se puede eliminar, encarecer ni pasar a otra moneda mientras lo use una factura reciente sin pagar o una compra en el bot pagada pero sin entregar. |
| 409 | key_exhausted | Rotación: la clave no tiene nada que mover, el resto es 0. |
| 409 | key_expired | Rotación: la clave venció, amplía primero su plazo. |
| 409 | action_failed | La acción sobre la clave falló por otro motivo; reintenta o revisa la clave. |
| 409 | code_used | El código ya está canjeado. |
| 409 | code_revoked | El código está revocado. |
| 409 | code_busy | El código se está procesando o no se puede canjear ahora. |
| 409 | external_order_id_conflict | external_order_id ya se usó con parámetros distintos. |
| 409 | customer_exists | Ya existe un cliente con este external_id. |
| 409 | customer_blocked | El cliente está bloqueado: se rechazan las claves, los pedidos y los canjes a su nombre. |
| 409 | token_limit | Se alcanzó el límite de tokens activos (10). |
| 409 | webhook_limit | Se alcanzó el límite de webhooks (5). |
| 429 | rate_limited | Más de 20 solicitudes por segundo por token (o 100 por segundo por dirección IP); espera los segundos indicados en Retry-After. |
| 429 | too_many_invoices | POST /balance/topups: demasiadas facturas sin pagar seguidas; paga las abiertas o reintenta en un minuto. |
| 501 | sandbox_not_implemented | El sandbox (rsk_test_...) aún no está implementado. |
| 503 | provider_unavailable | Un proveedor de pagos o de modelos no está disponible temporalmente: reintenta más tarde. |
Idempotencia
Los métodos que gastan dinero exigen el encabezado Idempotency-Key (de 1 a 128 caracteres imprimibles); sin él (o con uno no válido) la respuesta es 400 idempotency_key_required. Están marcados en la referencia. Repetir una solicitud con la misma clave y el mismo cuerpo (por revendedor) nunca gasta dos veces y devuelve el mismo objeto, incluido el secreto de la clave que creó esa llamada: una respuesta perdida por el camino se recupera repitiendo la llamada. La misma clave con otro cuerpo da 409 idempotency_key_reused. Usa una clave nueva para cada pago o pedido nuevo; en POST /orders la identidad es external_order_id. El encabezado es opcional (y se respeta si se envía) en PATCH /keys/{id} (un extend_days/extend_hours repetido amplía una sola vez), POST /plans y POST /webhooks (una repetición devuelve el mismo objeto; el secreto del webhook no se vuelve a mostrar).
curl -s -X POST https://app.oneprovider.dev/partner/v1/keys \
-H "Authorization: Bearer $OP_PARTNER_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"name":"client-1","limit_usd":"10.00"}' Guarda la clave de idempotencia junto con tu propio registro del pedido para que, tras un error de red, reintentes exactamente la misma solicitud.
Paginación
Los endpoints de listas aceptan ?limit=1..100 (por defecto 50) y &cursor=. La respuesta es {"items": [...], "next": "<cursor>"}; next es null en la última página. El cursor es opaco: devuélvelo tal cual.
curl -s "https://app.oneprovider.dev/partner/v1/keys?limit=100&cursor=<next from the previous page>" \
-H "Authorization: Bearer $OP_PARTNER_TOKEN" Sandbox
Los tokens de prueba rsk_test_... llegarán pronto. Por ahora un token así recibe 501 sandbox_not_implemented.