# Tiendas en línea

> Conecte Shopify, Mercado Libre o WooCommerce: cada pedido pagado se vuelve un ticket de autofactura, y lo que nadie factura entra en la factura global.

Cada pedido pagado de la tienda se vuelve un [ticket de autofactura](https://fiscalisto.com/docs/api/autofactura) del emisor, con el folio del pedido (`SHOP-1001`, `ML-2000001234`). Su comprador lo factura en el portal del emisor, y lo que nadie factura entra solo en la factura global del periodo. Un pedido cancelado, o reembolsado completo, cancela su ticket mientras nadie lo haya facturado.

| Tienda | Cómo se conecta | Dónde corre |
| --- | --- | --- |
| Shopify | `POST /v1/store_connections` con las llaves de la app de la tienda | En Fiscalisto: no instala nada |
| Mercado Libre | `POST /v1/store_connections` y el vendedor autoriza en Mercado Libre | En Fiscalisto |
| WooCommerce | El plugin **Fiscalisto Autofactura** en su WordPress | En su servidor, con `POST /v1/tickets` |

Un pedido llega una sola vez aunque la tienda lo mande varias: el folio es el mismo ticket. Solo se registran pedidos en pesos con total mayor a 0; los demás quedan en `last_error` de la conexión.

## Shopify

1. En el [Dev Dashboard](https://shopify.dev/docs/apps/build/dev-dashboard) de Shopify, cree una app en la organización de la tienda con los permisos `read_orders` y `write_orders`, e instálela en la tienda.
2. Conéctela con su Client ID y Client secret:

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/store_connections \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "shopify",
    "shop": "mi-tienda.myshopify.com",
    "client_id": "8c1f0e7a2b3d4e5f6a7b8c9d0e1f2a3b",
    "client_secret": "shpss_…",
    "settings": { "product_key": "53101600" }
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const storeConnection = await fiscalisto.storeConnections.create({
  platform: "shopify",
  shop: "mi-tienda.myshopify.com",
  client_id: "8c1f0e7a2b3d4e5f6a7b8c9d0e1f2a3b",
  client_secret: "shpss_…",
  settings: { product_key: "53101600" },
});
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

store_connection = fiscalisto.store_connections.create({
    "platform": "shopify",
    "shop": "mi-tienda.myshopify.com",
    "client_id": "8c1f0e7a2b3d4e5f6a7b8c9d0e1f2a3b",
    "client_secret": "shpss_…",
    "settings": {"product_key": "53101600"},
})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$storeConnection = $fiscalisto->storeConnections->create([
    'platform' => 'shopify',
    'shop' => 'mi-tienda.myshopify.com',
    'client_id' => '8c1f0e7a2b3d4e5f6a7b8c9d0e1f2a3b',
    'client_secret' => 'shpss_…',
    'settings' => ['product_key' => '53101600'],
]);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	storeConnection, err := client.StoreConnections.Create(ctx, &fiscalisto.CreateStoreConnectionParams{
		Platform:     "shopify",
		Shop:         fiscalisto.String("mi-tienda.myshopify.com"),
		ClientID:     fiscalisto.String("8c1f0e7a2b3d4e5f6a7b8c9d0e1f2a3b"),
		ClientSecret: fiscalisto.String("shpss_…"),
		Settings: &fiscalisto.CreateStoreConnectionParamsSettings{
			ProductKey: fiscalisto.String("53101600"),
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(storeConnection.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.CreateStoreConnectionParams;
import com.fiscalisto.model.CreateStoreConnectionParamsSettings;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var storeConnection = fiscalisto.storeConnections().create(new CreateStoreConnectionParams()
        .setPlatform("shopify")
        .setShop("mi-tienda.myshopify.com")
        .setClientId("8c1f0e7a2b3d4e5f6a7b8c9d0e1f2a3b")
        .setClientSecret("shpss_…")
        .setSettings(new CreateStoreConnectionParamsSettings()
                .setProductKey("53101600")));
System.out.println(storeConnection.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var storeConnection = await fiscalisto.StoreConnections.CreateAsync(new CreateStoreConnectionParams
{
    Platform = "shopify",
    Shop = "mi-tienda.myshopify.com",
    ClientId = "8c1f0e7a2b3d4e5f6a7b8c9d0e1f2a3b",
    ClientSecret = "shpss_…",
    Settings = new() { ProductKey = "53101600" },
});
```

Fiscalisto registra los webhooks de pedidos pagados, cancelados y reembolsos, y comprueba la firma de cada uno con el Client secret, que se guarda cifrado y nunca se muestra. Las llaves de la app solo sirven para tiendas de su misma organización de Shopify (`store_connection_failed` si no). Una app personalizada antigua, hecha en el admin de la tienda, se conecta con su token `shpat_…` en `access_token` y su API secret key en `client_secret`.

Cada pedido lleva su liga de autofactura en el metafield `fiscalisto.autofactura_url`. Para mostrarla en la página de estado del pedido y en el correo de confirmación, agréguela a sus plantillas:

```liquid
{% if order.metafields.fiscalisto.autofactura_url %}
  <a href="{{ order.metafields.fiscalisto.autofactura_url }}">Facturar mi compra</a>
{% endif %}
```

## Mercado Libre

Cree la conexión sin llaves. Queda `pending` con `authorize_url`: mande ahí al vendedor para que autorice a Fiscalisto en su cuenta de Mercado Libre. Al volver queda `active` (y, si mandó `return_url`, regresa a su página con `store_connection` y `status`).

```bash tab="cURL"
curl https://api.fiscalisto.com/v1/store_connections \
  -H "Authorization: Bearer $FISCALISTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "mercadolibre",
    "return_url": "https://su-plataforma.com/tiendas",
    "settings": { "product_key": "43211500" }
  }'
```

```ts tab="TypeScript"
import { Fiscalisto } from "fiscalisto";

// La llave viene de FISCALISTO_API_KEY.
const fiscalisto = new Fiscalisto();

const storeConnection = await fiscalisto.storeConnections.create({
  platform: "mercadolibre",
  return_url: "https://su-plataforma.com/tiendas",
  settings: { product_key: "43211500" },
});
```

```python tab="Python"
from fiscalisto import Fiscalisto

# La llave viene de FISCALISTO_API_KEY.
fiscalisto = Fiscalisto()

store_connection = fiscalisto.store_connections.create({
    "platform": "mercadolibre",
    "return_url": "https://su-plataforma.com/tiendas",
    "settings": {"product_key": "43211500"},
})
```

```php tab="PHP"
<?php

use Fiscalisto\Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
$fiscalisto = new Fiscalisto();

$storeConnection = $fiscalisto->storeConnections->create([
    'platform' => 'mercadolibre',
    'return_url' => 'https://su-plataforma.com/tiendas',
    'settings' => ['product_key' => '43211500'],
]);
```

```go tab="Go"
package main

import (
	"context"
	"fmt"
	"log"

	fiscalisto "fiscalisto.com/go"
)

func main() {
	// La llave viene de FISCALISTO_API_KEY.
	client, err := fiscalisto.NewClient("")
	if err != nil {
		log.Fatal(err)
	}
	ctx := context.Background()

	storeConnection, err := client.StoreConnections.Create(ctx, &fiscalisto.CreateStoreConnectionParams{
		Platform:  "mercadolibre",
		ReturnURL: fiscalisto.String("https://su-plataforma.com/tiendas"),
		Settings: &fiscalisto.CreateStoreConnectionParamsSettings{
			ProductKey: fiscalisto.String("43211500"),
		},
	})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(storeConnection.ID)
}
```

```java tab="Java"
import com.fiscalisto.FiscalistoClient;
import com.fiscalisto.model.CreateStoreConnectionParams;
import com.fiscalisto.model.CreateStoreConnectionParamsSettings;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var storeConnection = fiscalisto.storeConnections().create(new CreateStoreConnectionParams()
        .setPlatform("mercadolibre")
        .setReturnUrl("https://su-plataforma.com/tiendas")
        .setSettings(new CreateStoreConnectionParamsSettings()
                .setProductKey("43211500")));
System.out.println(storeConnection.getId());
```

```csharp tab="C#"
using Fiscalisto;

// La llave viene de FISCALISTO_API_KEY.
var fiscalisto = new FiscalistoClient();

var storeConnection = await fiscalisto.StoreConnections.CreateAsync(new CreateStoreConnectionParams
{
    Platform = "mercadolibre",
    ReturnUrl = "https://su-plataforma.com/tiendas",
    Settings = new() { ProductKey = "43211500" },
});
```

- Si el comprador dejó sus datos fiscales en Mercado Libre (RFC, nombre, régimen y código postal), la factura se timbra al pagarse el pedido. Si faltan, el ticket espera en el portal. Con `"auto_invoice": false` siempre espera.
- Cada factura de un pedido (la del comprador, timbrada aquí o en el portal) se sube a Mercado Libre como documento fiscal del pedido, con su XML y su PDF.
- Una cuenta de Mercado Libre se conecta a un solo emisor a la vez.

El total del ticket es el de los artículos (`total_amount`): el envío que cobra Mercado Libre no entra.

## Cómo se vuelve ticket cada pedido

`settings` decide el concepto y las claves del ticket. Se cambia con `POST /v1/store_connections/{id}` y cuenta desde el siguiente pedido.

| Campo | Qué hace |
| --- | --- |
| `product_key` | La c_ClaveProdServ de lo que vende. Obligatoria. |
| `unit_key`, `iva` | La c_ClaveUnidad y la tasa de IVA incluida en los precios (16 % si no la indica). |
| `description` | Un concepto fijo. Si no lo indica, el pedido y sus artículos: «Pedido 1001: Playera (2), Gorra». |
| `folio_prefix` | Lo que va antes del número del pedido: `SHOP-` o `ML-` si no lo indica. |
| `payment_forms` | La c_FormaPago de cada pasarela (`shopify_payments`, `paypal`…) o tipo de pago de Mercado Libre (`credit_card`, `debit_card`, `account_money`, `ticket`…). |
| `payment_form` | La que se usa cuando la del pedido no está en `payment_forms`. |

Sin `payment_forms`, una tarjeta de Shopify es 04, PayPal y Mercado Pago 31, el pago contra entrega 01 y el depósito 03. En Mercado Libre, crédito 04, débito 28, dinero en cuenta 06, efectivo 01 y transferencia 03; lo demás, 31 (intermediario de pagos). La propina de Shopify va en `tip` y no entra en la factura.

## Pedidos que no llegaron

Si conectó la tienda después de vender, o un webhook se perdió, `POST /v1/store_connections/{id}/import_orders` trae los pedidos pagados desde `since` (hasta 31 días atrás, 200 a la vez). Un pedido que ya era ticket no se repite.

## Desconectar

`DELETE /v1/store_connections/{id}` borra sus webhooks y sus llaves, y los pedidos dejan de llegar. Los tickets que ya hizo siguen y se pueden facturar.

## WooCommerce

El plugin **Fiscalisto Autofactura** corre en su WordPress con una llave de su cuenta API: registra cada pedido pagado con `POST /v1/tickets`, muestra la liga de autofactura en la página de gracias, en **Mi cuenta** y en los correos del pedido, y cancela el ticket si el pedido se cancela o se reembolsa completo. Si Fiscalisto no responde, lo reintenta solo. Se configura en **WooCommerce › Ajustes › Fiscalisto**. El plugin está en revisión en WordPress.org; en cuanto lo aprueben se instala desde Plugins › Añadir nuevo plugin.
