n1coePayDocs Referencia del API

SDK de React Native

@n1co/react-native cobra con tarjeta en apps de React Native y Expo: card field, código de seguridad, 3D Secure y tarjetas guardadas.

  1. Tu servidor crea el payment intent con tu llave secreta, sin page_origins, y entrega solo su client_secret a la app.
  2. La app muestra un CardField y llama a confirmPayment({ client_secret, card }).
  3. Tu servidor entrega el pedido con el webhook payment_intent.succeeded, nunca con lo que dice la app.

La tarjeta nunca se escribe en tu app. Cada campo es un WebView con la página de n1co, cuyos frames envían la tarjeta directo a n1co. Es solo JavaScript: funciona en Expo Go.

Instalar#

Expo

# Expo SDK 57 o 58: Expo Go, development builds, Expo Router
npx expo install react-native-webview expo-crypto react-native-get-random-values
npm install @n1co/react-native

React Native

# React Native 0.86 o posterior
npm install @n1co/react-native react-native-webview react-native-get-random-values
cd ios && pod install

La primera línea de la entrada de tu app (con Expo Router, app/_layout.tsx) es el polyfill de crypto.getRandomValues. Sin él, N1coProvider lanza crypto_unavailable.

import 'react-native-get-random-values';

Pagar con una tarjeta nueva#

app/_layout.tsx
import 'react-native-get-random-values';
import { useRef, useState } from 'react';
import { Button } from 'react-native';
import { CardField, N1coProvider, useN1co, type CardFieldHandle } from '@n1co/react-native';

// El Provider va una vez, en el layout raíz.
export default function RootLayout() {
  return (
    <N1coProvider publishableKey="pk_3x4mpl3pUbl1shabl3k3yAAAAAAAAAAA" host="https://elements.n1co.dev" locale="es">
      <Checkout />
    </N1coProvider>
  );
}

function Checkout() {
  const card = useRef<CardFieldHandle>(null);
  const [complete, setComplete] = useState(false);
  const { confirmPayment } = useN1co();

  async function pay() {
    const client_secret = await createIntentOnYourServer(); // tu endpoint
    try {
      const intent = await confirmPayment({ client_secret, card: card.current });
      if (intent.status === 'succeeded') showDone();
      else if (intent.status === 'processing') showPending();
      else showError(intent.last_error?.message); // rechazo o 3D Secure fallido: reintenta
    } catch (error) {
      showError((error as Error).message); // N1coError: decide con error.code
    }
  }

  return (
    <>
      <CardField ref={card} onChange={(event) => setComplete(event.complete)} />
      <Button title="Pagar" disabled={!complete} onPress={pay} />
    </>
  );
}

Sin host, el Provider usa el host de producción, que llega con el lanzamiento a producción. confirmPayment resuelve con el intent en un estado final, igual que en la web.

Tarjetas guardadas#

Si tu servidor adjuntó la tarjeta con payment_method, confirma con confirmPayment({ client_secret }). Con cvc_required: true, pide el código con un CvcField:

const cvc = useRef<CvcFieldHandle>(null);
<CvcField ref={cvc} options={{ brand: 'visa', last4: '4242' }} />;
await confirmPayment({ client_secret, cvc: cvc.current });

Para guardar una tarjeta, usa el client_secret de una sesión de tarjeta:

const { card: saved } = await card.current!.capture({ client_secret });
// saved: { id: 'card_…', brand, last4, exp_month, exp_year }

En modo actualización, <CardField options={{ update: { brand: 'visa', last4: '4242' } }} /> renueva vencimiento y código sin pedir el número.

3D Secure#

Si el banco lo pide, el paquete muestra su página en un modal sobre tu app: page sheet en iOS, pantalla completa en Android. El botón atrás de Android lo cierra; el intento falla y se puede reintentar.

Pon el Provider en el layout raíz, no dentro de una pantalla presentation: 'modal'.

Lo que suele fallar#

  • Enviar page_origins. Omítelo en los intents y sesiones que usa una app: la página que paga es de n1co, no tuya.
  • Pagar dos veces. Ver la advertencia de abajo.
  • Jest. El paquete trae ES modules: agrégalo a transformIgnorePatterns, por ejemplo node_modules/(?!((jest-)?react-native|@react-native|@n1co)/).

El paquete fija la configuración del WebView (navegación solo a n1co y al banco, sin scripts inyectados ni estado persistente) y no acepta props de WebView.

Los campos, sus eventos y todos los códigos de error están en el README del paquete.