<mxfile host="app.diagrams.net" agent="ApiPay Hub docs-portal" type="device" version="24.7.17">
  <diagram id="apipay-sdk-reintentos" name="Politica de reintentos de los SDKs">
    <mxGraphModel dx="1400" dy="1200" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="826" math="0" shadow="0">
      <root>
        <mxCell id="0" />
        <mxCell id="1" parent="0" />

        <mxCell id="lay-get" value="Camino de LECTURA - GET" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#F5F5F5;strokeColor=#9E9E9E;dashed=1;dashPattern=8 8;verticalAlign=top;align=left;spacingLeft=10;spacingTop=6;fontColor=#1A1A1A;fontSize=13;fontStyle=1" vertex="1" parent="1">
          <mxGeometry x="60" y="230" width="360" height="620" as="geometry" />
        </mxCell>
        <mxCell id="lay-post" value="Camino de ESCRITURA - POST" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#FDECEA;strokeColor=#C62828;dashed=1;dashPattern=8 8;verticalAlign=top;align=left;spacingLeft=10;spacingTop=6;fontColor=#B71C1C;fontSize=13;fontStyle=1" vertex="1" parent="1">
          <mxGeometry x="680" y="230" width="380" height="620" as="geometry" />
        </mxCell>

        <mxCell id="start" value="El SDK va a enviar una peticion a api.apipay.io" style="rounded=1;arcSize=40;whiteSpace=wrap;html=1;fillColor=#E8F5E9;strokeColor=#2E7D32;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="420" y="40" width="280" height="50" as="geometry" />
        </mxCell>
        <mxCell id="d1" value="El metodo es GET?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#FFF3E0;strokeColor=#EF6C00;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="410" y="120" width="300" height="90" as="geometry" />
        </mxCell>

        <mxCell id="g1" value="429, 5xx, o error de red&lt;br&gt;producido ANTES de enviar?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#FFF3E0;strokeColor=#EF6C00;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="80" y="270" width="320" height="110" as="geometry" />
        </mxCell>
        <mxCell id="g2" value="intentos usados &amp;lt; maxRetries?&lt;br&gt;maxRetries es 2 por defecto:&lt;br&gt;3 intentos en total" style="rhombus;whiteSpace=wrap;html=1;fillColor=#FFF3E0;strokeColor=#EF6C00;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="80" y="410" width="320" height="110" as="geometry" />
        </mxCell>
        <mxCell id="g3" value="espera = jitter completo sobre&lt;br&gt;min(500 ms x 2 potencia n, 8 s)&lt;br&gt;base 500 ms, factor 2, tope 8 s" style="rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#E3F2FD;strokeColor=#1565C0;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="80" y="550" width="320" height="70" as="geometry" />
        </mxCell>
        <mxCell id="g4" value="Si viene Retry-After Y el estado es&lt;br&gt;429 rate_limited o 503 gateway_unavailable,&lt;br&gt;manda Retry-After, con tope de 60 s" style="rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#E3F2FD;strokeColor=#1565C0;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="80" y="650" width="320" height="80" as="geometry" />
        </mxCell>
        <mxCell id="g5" value="Reintenta la MISMA peticion" style="rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#E3F2FD;strokeColor=#1565C0;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="80" y="770" width="320" height="55" as="geometry" />
        </mxCell>

        <mxCell id="p1" value="Se recibio respuesta,&lt;br&gt;o no consta si el POST llego?" style="rhombus;whiteSpace=wrap;html=1;fillColor=#FFF3E0;strokeColor=#EF6C00;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="700" y="270" width="340" height="110" as="geometry" />
        </mxCell>
        <mxCell id="p2" value="NO se reintenta NUNCA&lt;br&gt;ni con 429, ni con 503, ni con timeout" style="rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#FFCDD2;strokeColor=#C62828;fontColor=#1A1A1A;fontSize=11;fontStyle=1" vertex="1" parent="1">
          <mxGeometry x="700" y="410" width="340" height="60" as="geometry" />
        </mxCell>
        <mxCell id="p3" value="El SDK devuelve el error tipado&lt;br&gt;y la Idempotency-Key (UUID v4) que genero:&lt;br&gt;la EXPONE en el resultado, no la esconde" style="rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#E3F2FD;strokeColor=#1565C0;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="700" y="500" width="340" height="80" as="geometry" />
        </mxCell>
        <mxCell id="p4" value="El comercio la persiste y reintenta&lt;br&gt;con la MISMA Idempotency-Key:&lt;br&gt;ese si es un reintento seguro" style="rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#C8E6C9;strokeColor=#2E7D32;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="700" y="610" width="340" height="70" as="geometry" />
        </mxCell>
        <mxCell id="p5" value="Reintentar con una clave NUEVA = cargo duplicado" style="rounded=1;arcSize=12;whiteSpace=wrap;html=1;fillColor=#FFCDD2;strokeColor=#C62828;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="700" y="710" width="340" height="55" as="geometry" />
        </mxCell>

        <mxCell id="end" value="Resultado, o ApiPayError con code, status,&lt;br&gt;el problem completo y el requestId de X-Request-Id" style="rounded=1;arcSize=40;whiteSpace=wrap;html=1;fillColor=#E8F5E9;strokeColor=#2E7D32;fontColor=#1A1A1A;fontSize=11" vertex="1" parent="1">
          <mxGeometry x="410" y="880" width="320" height="70" as="geometry" />
        </mxCell>

        <mxCell id="razon" value="Por que la asimetria es deliberada: reintentar automaticamente un POST de cobro es exactamente como se duplican los cargos. El SDK no puede saber si el cargo se ejecuto, asi que no adivina; entrega la clave de idempotencia y deja el reintento en manos del comercio, que si puede decidir. La logica de negocio se escribe siempre contra el campo code del catalogo, jamas contra detail, que es texto para humanos y puede cambiar sin aviso." style="shape=note;size=16;whiteSpace=wrap;html=1;fillColor=#FDECEA;strokeColor=#C62828;fontColor=#1A1A1A;fontSize=11;align=left;verticalAlign=top;spacingLeft=8;spacingTop=4" vertex="1" parent="1">
          <mxGeometry x="60" y="990" width="1000" height="90" as="geometry" />
        </mxCell>
        <mxCell id="plataforma" value="Matiz de plataforma en la clausula del error de red previo al envio: Python y Java la implementan, porque sus clientes distinguen el fallo de conexion (ConnectError, ConnectException). TypeScript y PHP no pueden: ni fetch ni la NetworkExceptionInterface de PSR-18 separan pre-envio de post-envio, y ante la duda no reintentan. Esa mitad estricta es MAS conservadora que el contrato, nunca menos segura." style="shape=note;size=16;whiteSpace=wrap;html=1;fillColor=#FFFDE7;strokeColor=#F9A825;fontColor=#1A1A1A;fontSize=11;align=left;verticalAlign=top;spacingLeft=8;spacingTop=4" vertex="1" parent="1">
          <mxGeometry x="60" y="1100" width="1000" height="90" as="geometry" />
        </mxCell>

        <mxCell id="e-start-d1" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="start" target="d1">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="e-d1-g1" value="si - GET, lectura idempotente" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="d1" target="g1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="240" y="165" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e-d1-p1" value="no - POST de create, confirm, cancel o refund" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#C62828;fontColor=#B71C1C;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="d1" target="p1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="870" y="165" />
            </Array>
          </mxGeometry>
        </mxCell>

        <mxCell id="e-g1-g2" value="si" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="g1" target="g2">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="e-g1-end" value="no - 2xx u otro 4xx" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#2E7D32;fontColor=#1B5E20;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0" edge="1" parent="1" source="g1" target="end">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="30" y="325" />
              <mxPoint x="30" y="915" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e-g2-g3" value="si" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="g2" target="g3">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="e-g2-end" value="no - intentos agotados" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.1;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="g2" target="end">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="442" y="465" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e-g3-g4" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="g3" target="g4">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="e-g4-g5" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="g4" target="g5">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="e-g5-g1" value="y se vuelve a evaluar" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0" edge="1" parent="1" source="g5" target="g1">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="412" y="797" />
              <mxPoint x="412" y="325" />
            </Array>
          </mxGeometry>
        </mxCell>

        <mxCell id="e-p1-p2" value="si, en cualquiera de los dos casos" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#C62828;fontColor=#B71C1C;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="p1" target="p2">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="e-p2-p3" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="p2" target="p3">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="e-p3-p4" value="entrega la clave al llamador" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#2E7D32;fontColor=#1B5E20;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="p3" target="p4">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="e-p4-p5" value="jamas con otra clave" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;dashed=1;strokeColor=#C62828;fontColor=#B71C1C;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0" edge="1" parent="1" source="p4" target="p5">
          <mxGeometry relative="1" as="geometry" />
        </mxCell>
        <mxCell id="e-p3-end" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;strokeColor=#455A64;fontColor=#1A1A1A;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0" edge="1" parent="1" source="p3" target="end">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="660" y="540" />
              <mxPoint x="660" y="915" />
            </Array>
          </mxGeometry>
        </mxCell>
        <mxCell id="e-p2-razon" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;html=1;jettySize=auto;orthogonalLoop=1;dashed=1;strokeColor=#C62828;fontColor=#B71C1C;fontSize=10;labelBackgroundColor=#FFFFFF;endArrow=block;endFill=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0" edge="1" parent="1" source="p2" target="razon">
          <mxGeometry relative="1" as="geometry">
            <Array as="points">
              <mxPoint x="1090" y="440" />
              <mxPoint x="1090" y="1035" />
            </Array>
          </mxGeometry>
        </mxCell>
      </root>
    </mxGraphModel>
  </diagram>
</mxfile>
