Documentación para desarrolladores
API reference
La API raíz autentica al comercio mediante una clave de servidor y devuelve JSON con request_id para correlación.
Convenciones de la API
| Elemento | Contrato |
|---|---|
| Base URL | https://api.andorpay.com/v1 |
| Autenticación | Authorization: Bearer <ANDORPAY_API_KEY> |
| Entorno | ap_test_ usa sandbox y ap_live_ usa producción. El entorno es inmutable para la clave. |
| Versión del cliente | Andorpay-Version: 2026-01-01 |
| Cuerpo | JSON con un límite global de 100 KB para peticiones interpretadas por la API. |
| Correlación | La respuesta incluye request_id y también envía x-request-id y x-andorpay-flow-id cuando están disponibles. |
La cabecera Andorpay-Version forma parte de los clientes y ejemplos actuales. El código revisado no implementa todavía una negociación global de versiones; no dependas de que otra fecha seleccione un contrato distinto.
POST /v1/checkouts
Crea una sesión de checkout alojado vinculada al entorno de la API key. No admite Idempotency-Key y devuelve 400checkout_idempotency_key_not_allowed si la cabecera está presente.
| Campo | Tipo | Requerido | Regla |
|---|---|---|---|
productId | string | Sí | Producto activo del comercio. Máximo 200 caracteres. |
externalCustomerId | string | Sí | Referencia estable del cliente en tu sistema. Máximo 160 caracteres. |
customer | object | No | Prefill del comprador. Si falta email, el checkout alojado lo solicita. |
customer.email | string | No | Email de prefill. Máximo 320 caracteres. |
customer.name | string | No | Nombre de prefill. Máximo 160 caracteres. |
customer.billingDetails | object | No | Dirección de facturación. Admite line1, line2, city, region, postal_code y country. |
customer.tax.value | string | No | Identificador fiscal que se precarga en el checkout. |
customer.tax.type | string | No | Tipo del identificador fiscal. |
amount | integer | No | Céntimos positivos, nunca por encima del precio activo. No se admite si el precio define trial. |
successUrl | URL | No | Máximo 500 caracteres. HTTPS, excepto HTTP en localhost o 127.0.0.1. |
failUrl | URL | No | Mismas reglas que successUrl. |
reconciliation.merchantReference | string | No | Referencia operativa del carrito o pedido. Máximo 120 caracteres. |
curl https://api.andorpay.com/v1/checkouts \
--request POST \
--header "Authorization: Bearer $ANDORPAY_API_KEY" \
--header "Andorpay-Version: 2026-01-01" \
--header "Content-Type: application/json" \
--data '{
"productId": "ap_prod_starter_monthly",
"externalCustomerId": "customer_42",
"customer": {
"email": "ana@example.com",
"name": "Ana Garcia",
"billingDetails": {
"line1": "Carrer Prat de la Creu 12",
"city": "Andorra la Vella",
"postal_code": "AD500",
"country": "AD"
},
"tax": {
"value": "F-123456-Z",
"type": "andorra_nrt"
}
},
"successUrl": "https://shop.example.com/payment/success",
"failUrl": "https://shop.example.com/payment/failed",
"reconciliation": {
"merchantReference": "cart_1048"
}
}'| Campo de respuesta | Tipo | Significado |
|---|---|---|
id | string | Identificador interno de la sesión. |
sessionId | string | Identificador público de la sesión alojada. |
hostedUrl | URL | URL completa que debe abrir el navegador. |
expiresAt | ISO 8601 | Caducidad de la sesión, 30 minutos después de crearla. |
request_id | string | Identificador para soporte y correlación. |
{
"id": "ap_chk_01JQ8P9A3Y9B5J7V2V0M9R4S8T",
"sessionId": "ap_chk_01JQ8P9A3Y9B5J7V2V0M9R4S8T",
"hostedUrl": "https://shop.andorpay.com/checkout/ap_chk_01JQ8P9A3Y9B5J7V2V0M9R4S8T",
"expiresAt": "2026-08-23T11:30:00.000Z",
"request_id": "req_01JQ8T2M0D6F4Q7F3K8A9V2N1C"
}| Estado | Código frecuente | Significado |
|---|---|---|
| 201 | - | Sesión creada. |
| 400 | checkout_productId_required | Falta productId. |
| 400 | checkout_externalCustomerId_required | Falta externalCustomerId. |
| 400 | price_id_not_allowed | El precio se resuelve desde productId. |
| 400 | checkout_amount_invalid | El importe no es un entero positivo en céntimos. |
| 400 | checkout_amount_exceeds_price | El importe supera el precio activo. |
| 400 | checkout_amount_not_allowed_with_trial | El trial forma parte del precio y no admite override. |
| 403 | merchant_feature_not_enabled | El producto recurrente requiere la capacidad de suscripciones. |
| 404 | product_not_found | El producto no existe o está inactivo. |
| 409 | payment_rail_activation_in_progress | La configuración Redsys todavía se está activando. |
| 503 | payment_rail_unavailable | No existe una cuenta de rail válida para ese entorno y operación. |
Recursos de billing
| Endpoint | Respuesta 200 |
|---|---|
GET /v1/products | { data: Product[], request_id } |
GET /v1/orders | { data: Order[], request_id } |
GET /v1/payments | { data: Payment[], request_id } sin credential_secret_ref |
GET /v1/subscriptions | { data: Subscription[], request_id } |
GET /v1/subscriptions/current | Alias actual de la lista completa de suscripciones. |
GET /v1/invoices | { data: Invoice[], request_id } |
GET /v1/billing/dashboard | Contadores merchant_id, orders, payments, invoices y subscriptions si está habilitado. |
| Recurso | Campos públicos principales |
|---|---|
| Product | id, merchant_id, name, description, metadata, external_reference, active_price, status, created_at, updated_at |
| Price | id, product_id, amount, currency, tax_rate, billing_mode, recurring, status |
| Order | id, customer_id, product_id, price_id, source, external_reference, line_items, amount, currency, payment_id, status |
| Payment | id, order_id, rail_account_id, rail_order_id, rail, payment_method, status, amount, currency, failure fields and timestamps |
| Subscription | id, customer_id, product_id, plan and offering identity, status, periods, amount, currency, payment method, cancellation and trial fields |
| Invoice | id, number, issued_at, customer_id, order_id, subscription_id, status, amount_due, currency, customer, line_items, pdf_url |
Las rutas de lista no implementan paginación ni filtros en el router revisado. No envíes parámetros esperando que reduzcan el conjunto hasta que exista un contrato público explícito.
POST /v1/payment-methods/change
Crea una acción alojada para actualizar el método reutilizable de una suscripción. Requiere la capacidad de suscripciones, inSite y un rail con recurrencia o mandates.
| Campo | Requerido | Regla |
|---|---|---|
subscriptionId | Sí | Suscripción que pertenece al mismo cliente y comercio. |
externalCustomerId | Sí | Referencia del cliente en tu sistema. |
customer.email | Sí | Email del cliente; name, billingDetails y tax son opcionales. |
successUrl | Sí | HTTPS, salvo localhost o 127.0.0.1 durante desarrollo. |
failUrl | Sí | Mismas reglas que successUrl. |
La respuesta 201 contiene id, customerId, hostedUrl, expiresAt yrequest_id. La acción caduca en 15 minutos. Espera payment_method.updated opayment_method.update_failed para confirmar el resultado.
Operaciones de suscripción
| Endpoint | Cuerpo | Idempotencia | Respuesta |
|---|---|---|---|
POST /v1/subscriptions/:id/cancel | Sin campos requeridos | No requiere cabecera | 200 Subscription, 404 si no existe, 409 si hay un cambio programado incompatible |
POST /v1/subscriptions/:id/plan-change | target_plan_id; target_product_id es alias legacy | Idempotency-Key obligatorio | 202 Subscription con change |
POST /v1/subscriptions/:id/offering-change | target_offering_id y target_plan_id | Idempotency-Key obligatorio | 202 cambio programado |
POST /v1/subscriptions/:id/plan-change/cancel | action_id | Idempotency-Key obligatorio | 200 con status cancelled |
Una clave idempotente se reutiliza sólo al reintentar la misma operación con el mismo cuerpo. Cambiar el objetivo exige una clave nueva.
POST /v1/refunds
El endpoint define un reembolso durable y exige Idempotency-Key. Sin embargo, el adaptador Redsys actual declara que los reembolsos no están soportados y responde 501 antes de enviar una operación al proveedor.
| Campo | Requerido | Regla |
|---|---|---|
paymentId | paymentId u orderId | Pago liquidado del comercio. |
orderId | paymentId u orderId | Resuelve el pago asociado al pedido. |
amount | No | Céntimos enteros positivos. Por defecto, el importe completo. |
currency | No | Si se envía, debe coincidir con la moneda del pago. |
reason | No | Motivo operativo. |
Formato de errores
{
"code": "product_not_found",
"message": "Product not found or inactive",
"request_id": "req_01JQ8T2M0D6F4Q7F3K8A9V2N1C"
}| Estado | Interpretación |
|---|---|
| 400 | Entrada o cabecera inválida. Corrige la petición antes de reintentar. |
| 401 | API key ausente o inválida. |
| 403 | Comercio, entorno o capacidad no autorizada. |
| 404 | Recurso no encontrado dentro del comercio autenticado. |
| 409 | Conflicto de estado o de una operación en curso. |
| 422 | Contrato financiero inconsistente, como un precio recurrente sin intervalo. |
| 500 | Fallo interno redacted. Conserva request_id. |
| 501 | Capacidad de proveedor no implementada, actualmente reembolsos Redsys. |
| 503 | Dependencia o capacidad temporalmente no disponible. |
Limitaciones verificadas
POST /v1/manual-charges sólo crea un registro local de pago en estado processing; el caso de uso revisado no ejecuta una autorización Redsys. No se documenta como forma de cobrar.
Las rutas PATCH /v1/invoice-settings devuelven el cuerpo recibido, pero el router revisado no persiste el cambio. Las rutas con /v1/merchants/:merchantId son contratos administrativos o de compatibilidad; las integraciones de comercio deben preferir los endpoints raíz autenticados.
El OpenAPI incluido en el repositorio describe el checkout público, pero todavía no cubre todos los cuerpos de las rutas disponibles. Esta página sigue el router y los casos de uso ejecutados por la API.