{"openapi":"3.1.0","info":{"title":"Arkax Card Payments API","version":"1.3.1","description":"API server-to-server de pagos con checkout alojado. El prefijo de la API key selecciona un espacio de datos aislado: akx_test_ usa el simulador y akx_live_ usa el procesador real."},"servers":[{"url":"https://checkout.arkax.app","description":"API principal; la API key selecciona TEST o LIVE"},{"url":"https://sandbox-checkout.arkax.app","description":"QA de la plataforma Arkax; no es necesario para integrar el modo TEST"}],"tags":[{"name":"Payment sessions"},{"name":"Payments"},{"name":"Payment links"},{"name":"Webhooks"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key server-to-server del tenant: akx_test_... o akx_live_..."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":true,"description":"Clave única de la operación. Máximo 128 caracteres; reutilizar solo para reintentar exactamente la misma solicitud durante 24 horas.","schema":{"type":"string","minLength":1,"maxLength":128},"example":"order-1842-create-session"},"PaymentId":{"name":"paymentId","in":"path","required":true,"schema":{"type":"string","minLength":1},"description":"ID del pago devuelto en payment.id."}},"schemas":{"Metadata":{"type":"object","maxProperties":50,"propertyNames":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9_.:-]+$"},"additionalProperties":true,"default":{},"description":"Objeto JSON privado del comercio, máximo 8 KB serializados. Los valores pueden ser cualquier valor JSON. Se devuelve por API y webhooks; no se muestra al pagador. No incluir datos de tarjeta ni secretos."},"Customer":{"type":"object","additionalProperties":false,"required":["email","first_name","last_name"],"properties":{"email":{"type":"string","format":"email","example":"ada@example.com"},"first_name":{"type":"string","minLength":1,"maxLength":80,"example":"Ada"},"last_name":{"type":"string","minLength":1,"maxLength":80,"example":"Lovelace"},"phone":{"type":"string","pattern":"^\\+?[0-9]{7,15}$","example":"+525512345678"}}},"PaymentStatus":{"type":"string","enum":["created","processing","requires_action","approved","declined","unknown","expired","partially_refunded","refunded","reversed"]},"OperationStatus":{"type":"string","enum":["pending","approved","declined","unknown"]},"Payment":{"type":"object","required":["id","object","livemode","reference","amount","currency","status","order_id","transaction_id","decline_reason","card_brand","card_last_four","metadata","created_at","updated_at"],"properties":{"id":{"type":"string","example":"cms..."},"object":{"type":"string","const":"payment"},"livemode":{"type":"boolean","description":"false para recursos creados con akx_test_; true para akx_live_."},"reference":{"type":"string","minLength":3,"maxLength":30,"example":"ORDER-2026-1842-A1"},"amount":{"type":"integer","minimum":20000,"maximum":600000,"description":"Unidades menores. 20100 representa MXN 201.00.","example":20100},"currency":{"type":"string","pattern":"^[0-9]{3}$","example":"484"},"status":{"$ref":"#/components/schemas/PaymentStatus"},"order_id":{"type":["string","null"],"description":"ID canónico de la orden en el procesador."},"transaction_id":{"type":["string","null"],"description":"ID de transacción del procesador."},"decline_reason":{"type":["string","null"],"description":"Motivo sanitizado disponible cuando el pago no fue aprobado."},"card_brand":{"type":["string","null"],"enum":["visa","mastercard","amex","discover","diners","jcb","unionpay","unknown",null],"description":"Marca detectada de la tarjeta. Es null hasta que el comprador envía el formulario."},"card_last_four":{"type":["string","null"],"pattern":"^[0-9]{4}$","description":"Últimos cuatro dígitos para conciliación. Arkax nunca devuelve el PAN completo ni el CVV."},"metadata":{"$ref":"#/components/schemas/Metadata"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"PaymentSessionInput":{"type":"object","additionalProperties":false,"required":["amount","reference","customer","return_url","allowed_origin"],"properties":{"amount":{"type":"integer","minimum":20000,"maximum":600000,"description":"Importe en unidades menores; 20100 representa MXN 201.00.","example":20100},"currency":{"type":"string","pattern":"^[0-9]{3}$","default":"484","description":"Código ISO 4217 numérico; actualmente MXN 484."},"reference":{"type":"string","minLength":3,"maxLength":30,"description":"Referencia única por intento dentro del tenant y modo (TEST o LIVE). El procesador admite máximo 30 caracteres; usa metadata para IDs internos más largos.","example":"ORDER-2026-1842-A1"},"metadata":{"$ref":"#/components/schemas/Metadata"},"customer":{"$ref":"#/components/schemas/Customer"},"return_url":{"type":"string","format":"uri","description":"URL HTTPS de retorno del comercio; localhost HTTP solo en desarrollo."},"allowed_origin":{"type":"string","format":"uri","description":"Origen exacto autorizado para el iframe, por ejemplo https://tienda.example. El path se descarta al validar."},"expires_in":{"type":"integer","minimum":300,"maximum":86400,"default":1800,"description":"Vigencia de la sesión en segundos."}}},"PaymentSession":{"type":"object","required":["id","object","client_secret","checkout_url","expires_at","payment"],"properties":{"id":{"type":"string"},"object":{"type":"string","const":"payment_session"},"client_secret":{"type":"string","description":"Token efímero que puede entregarse al navegador para montar el checkout."},"checkout_url":{"type":"string","format":"uri"},"expires_at":{"type":"string","format":"date-time"},"payment":{"$ref":"#/components/schemas/Payment"}}},"PaymentLinkInput":{"type":"object","additionalProperties":false,"required":["amount","reference","return_url","allowed_origin","expires_at"],"properties":{"amount":{"type":"integer","minimum":20000,"maximum":600000,"description":"Importe en unidades menores.","example":20100},"currency":{"type":"string","pattern":"^[0-9]{3}$","default":"484"},"reference":{"type":"string","minLength":3,"maxLength":21,"description":"Referencia única por tenant y modo; visible para el pagador. Arkax reserva 9 caracteres para el identificador único del intento enviado al procesador."},"description":{"type":"string","maxLength":240,"description":"Concepto visible para el pagador."},"metadata":{"$ref":"#/components/schemas/Metadata"},"return_url":{"type":"string","format":"uri"},"allowed_origin":{"type":"string","format":"uri","description":"Origen registrado del comercio."},"expires_at":{"type":"string","format":"date-time","description":"Debe ser una fecha futura."}}},"PaymentLink":{"type":"object","required":["id","object","livemode","url","amount","currency","reference","description","metadata","active","expires_at","consumed_at"],"properties":{"id":{"type":"string"},"object":{"type":"string","const":"payment_link"},"livemode":{"type":"boolean"},"url":{"type":"string","format":"uri"},"amount":{"type":"integer"},"currency":{"type":"string"},"reference":{"type":"string","minLength":3,"maxLength":21},"description":{"type":["string","null"]},"metadata":{"$ref":"#/components/schemas/Metadata"},"active":{"type":"boolean"},"expires_at":{"type":"string","format":"date-time"},"consumed_at":{"type":["string","null"],"format":"date-time"}}},"RefundInput":{"type":"object","additionalProperties":false,"required":["amount"],"properties":{"amount":{"type":"integer","minimum":1,"description":"Importe a reembolsar en unidades menores."}}},"Refund":{"type":"object","required":["id","object","livemode","payment_id","amount","status","created_at"],"properties":{"id":{"type":"string"},"object":{"type":"string","const":"refund"},"livemode":{"type":"boolean"},"payment_id":{"type":"string"},"amount":{"type":"integer"},"status":{"$ref":"#/components/schemas/OperationStatus"},"created_at":{"type":"string","format":"date-time"}}},"Reversal":{"type":"object","required":["id","object","livemode","payment_id","status","created_at"],"properties":{"id":{"type":"string"},"object":{"type":"string","const":"reversal"},"livemode":{"type":"boolean"},"payment_id":{"type":"string"},"status":{"$ref":"#/components/schemas/OperationStatus"},"created_at":{"type":"string","format":"date-time"}}},"WebhookEventType":{"type":"string","enum":["payment.processing","payment.requires_action","payment.succeeded","payment.failed","payment.unknown","payment.partially_refunded","payment.refunded","payment.reversed"]},"WebhookEndpointInput":{"type":"object","additionalProperties":false,"required":["url","events"],"properties":{"url":{"type":"string","format":"uri","description":"URL HTTPS pública; no se admiten localhost ni redes privadas."},"description":{"type":"string","maxLength":120},"events":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/WebhookEventType"}}}},"WebhookEndpoint":{"type":"object","required":["id","object","livemode","url","description","events","active","created_at"],"properties":{"id":{"type":"string"},"object":{"type":"string","const":"webhook_endpoint"},"livemode":{"type":"boolean"},"url":{"type":"string","format":"uri"},"description":{"type":["string","null"]},"events":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEventType"}},"active":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"},"secret":{"type":"string","writeOnly":true,"description":"Solo está presente en la respuesta de creación y se muestra una vez."}}},"PaymentLinkUpdateInput":{"type":"object","additionalProperties":false,"required":["active"],"properties":{"active":{"type":"boolean","description":"Activa o desactiva el link. Un link consumido no puede reactivarse."}}},"PaymentLinkUpdate":{"type":"object","required":["id","active"],"properties":{"id":{"type":"string"},"active":{"type":"boolean"}}},"WebhookEndpointUpdateInput":{"type":"object","additionalProperties":false,"properties":{"active":{"type":"boolean"},"rotate_secret":{"type":"boolean","description":"Si es true genera un secreto nuevo e invalida el anterior."}},"anyOf":[{"required":["active"]},{"required":["rotate_secret"],"properties":{"rotate_secret":{"const":true}}}]},"WebhookEndpointUpdate":{"type":"object","required":["id","active"],"properties":{"id":{"type":"string"},"active":{"type":"boolean"},"secret":{"type":"string","writeOnly":true,"description":"Solo aparece al rotar y se muestra una vez."}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","example":"validation_error"},"message":{"type":"string","example":"Request validation failed"},"details":{"description":"Detalles estructurados opcionales, por ejemplo issues de validación."}}}}}},"responses":{"BadRequest":{"description":"Solicitud inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"API key ausente o inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Scope ausente, tenant inactivo u origen no autorizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Recurso no encontrado para el tenant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"Conflicto de idempotencia o estado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unprocessable":{"description":"La operación no cumple las reglas del procesador","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Límite excedido; respetar Retry-After","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/v1/payment-sessions":{"post":{"tags":["Payment sessions"],"operationId":"createPaymentSession","summary":"Crear una sesión de checkout alojado","description":"Requiere scope payment_sessions:create. La API key permanece en el backend; entrega únicamente client_secret al navegador.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentSessionInput"}}}},"responses":{"201":{"description":"Sesión creada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentSession"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/payments/{paymentId}":{"get":{"tags":["Payments"],"operationId":"getPayment","summary":"Consultar el estado canónico de un pago","description":"Requiere scope payments:read. Incluye metadata privada del comercio.","parameters":[{"$ref":"#/components/parameters/PaymentId"}],"responses":{"200":{"description":"Pago","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Payment"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/payments/{paymentId}/refunds":{"post":{"tags":["Payments"],"operationId":"createRefund","summary":"Crear un reembolso total","description":"Requiere scope refunds:create. amount debe coincidir con el saldo reembolsable completo. Después del día operativo del pago; para el mismo día usa reversal.","parameters":[{"$ref":"#/components/parameters/PaymentId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundInput"}}}},"responses":{"201":{"description":"Reembolso creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refund"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"}}}},"/v1/payments/{paymentId}/reversal":{"post":{"tags":["Payments"],"operationId":"createReversal","summary":"Reversar completamente un pago del mismo día operativo","description":"Requiere scope reversals:create. No requiere body.","parameters":[{"$ref":"#/components/parameters/PaymentId"},{"$ref":"#/components/parameters/IdempotencyKey"}],"responses":{"201":{"description":"Reversal creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Reversal"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/payment-links":{"get":{"tags":["Payment links"],"operationId":"listPaymentLinks","summary":"Listar los 100 links más recientes","description":"Requiere scope payment_links:write.","responses":{"200":{"description":"Lista de links","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PaymentLink"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Payment links"],"operationId":"createPaymentLink","summary":"Crear un link de pago de un solo uso","description":"Requiere scope payment_links:write. Description y reference se muestran al pagador; metadata permanece privada.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentLinkInput"}}}},"responses":{"201":{"description":"Link creado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentLink"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/payment-links/{linkId}":{"patch":{"tags":["Payment links"],"operationId":"updatePaymentLink","summary":"Activar o desactivar un link","description":"Requiere scope payment_links:write. Los links consumidos o que ya originaron un pago no pueden reactivarse.","parameters":[{"name":"linkId","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentLinkUpdateInput"}}}},"responses":{"200":{"description":"Link actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaymentLinkUpdate"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/webhook-endpoints":{"get":{"tags":["Webhooks"],"operationId":"listWebhookEndpoints","summary":"Listar endpoints webhook","description":"Requiere scope webhooks:write. Los secretos no se vuelven a mostrar.","responses":{"200":{"description":"Lista de endpoints","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Webhooks"],"operationId":"createWebhookEndpoint","summary":"Registrar un endpoint webhook firmado","description":"Requiere scope webhooks:write. El secret se devuelve una sola vez en la respuesta de creación.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointInput"}}}},"responses":{"201":{"description":"Endpoint creado; secret presente una sola vez","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/webhook-endpoints/{endpointId}":{"patch":{"tags":["Webhooks"],"operationId":"updateWebhookEndpoint","summary":"Activar, desactivar o rotar el secreto de un webhook","description":"Requiere scope webhooks:write. Si se rota, el secret nuevo se devuelve una sola vez.","parameters":[{"name":"endpointId","in":"path","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointUpdateInput"}}}},"responses":{"200":{"description":"Endpoint actualizado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointUpdate"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}}}}