Documentación de API

Integra el potente motor de precios de Grula en tus aplicaciones con nuestra API REST completa. Calcula precios, gestiona políticas de precios y configura ajustes dinámicos programáticamente.

Inicio rápido

Comienza con la API de Grula en minutos. Todo lo que necesitas es un token de API para empezar a hacer solicitudes.

Autenticación

Todas las solicitudes de API requieren autenticación usando un token Bearer. Puedes generar tu token de API desde el panel de Grula.

Authorization: Bearer YOUR_API_TOKEN

URL base

https://api.grula.net

Conceptos clave

Políticas de precios (listas de precios)

Las políticas de precios definen tus precios base para productos o servicios. Piensa en ellas como tus listas de precios que contienen las reglas fundamentales de precios para tu negocio.

Políticas de ajuste de precios (descuentos y recargos)

Las políticas de ajuste de precios modifican tus precios base aplicando descuentos, recargos u otros ajustes según condiciones específicas como el tipo de cliente, el volumen o factores estacionales.

Get PricePOST

Calcula un precio a partir de factores de precio, una moneda y una fecha de precio opcional. Es el endpoint principal para el cálculo de precios en tiempo real.

Endpoint

POST /api/v1/price
curl -X POST "https://api.grula.net/api/v1/price" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "environmentId": "123e4567-e89b-12d3-a456-426614174000",
    "priceDrivers": [
      {
        "name": "product",
        "value": "laptop"
      },
      {
        "name": "customer_tier",
        "value": "premium"
      }
    ],
    "currencyThreeLetterCode": "USD",
    "pricingDate": "2024-01-15T10:00:00Z"
  }'
import requests
    import json

    url = "https://api.grula.net/api/v1/price"
    headers = {
        "Authorization": "Bearer YOUR_API_TOKEN",
        "Content-Type": "application/json"
    }

    payload = {
        "environmentId": "123e4567-e89b-12d3-a456-426614174000",
        "priceDrivers": [
            {
                "name": "product",
                "value": "laptop"
            },
            {
                "name": "customer_tier",
                "value": "premium"
            }
        ],
        "currencyThreeLetterCode": "USD",
        "pricingDate": "2024-01-15T10:00:00Z"
    }

    response = requests.post(url, headers=headers, json=payload)
    price_data = response.json()
    print(f"Price: {price_data['amount']['amount']} {price_data['amount']['currencyThreeLetterCode']}")
const axios = require('axios');

    const getPricing = async () => {
      try {
        const response = await axios.post('https://api.grula.net/api/v1/price', {
          environmentId: '123e4567-e89b-12d3-a456-426614174000',
          priceDrivers: [
            {
              name: 'product',
              value: 'laptop'
            },
            {
              name: 'customer_tier',
              value: 'premium'
            }
          ],
          currencyThreeLetterCode: 'USD',
          pricingDate: '2024-01-15T10:00:00Z'
        }, {
          headers: {
            'Authorization': 'Bearer YOUR_API_TOKEN',
            'Content-Type': 'application/json'
          }
        });
    
        console.log(`Price: ${response.data.amount.amount} ${response.data.amount.currencyThreeLetterCode}`);
        return response.data;
      } catch (error) {
        console.error('Error fetching price:', error.response?.data || error.message);
      }
    };

    getPricing();
using System;
    using System.Net.Http;
    using System.Text;
    using System.Text.Json;
    using System.Threading.Tasks;

    public class PricingClient
    {
        private readonly HttpClient _httpClient;
        private const string BaseUrl = "https://api.grula.net";

        public PricingClient(string apiToken)
        {
            _httpClient = new HttpClient();
            _httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiToken}");
        }

        public async Task<PriceResponse> GetPriceAsync(PriceRequest request)
        {
            var json = JsonSerializer.Serialize(request);
            var content = new StringContent(json, Encoding.UTF8, "application/json");
        
            var response = await _httpClient.PostAsync($"{BaseUrl}/api/v1/price", content);
            response.EnsureSuccessStatusCode();
        
            var responseJson = await response.Content.ReadAsStringAsync();
            return JsonSerializer.Deserialize<PriceResponse>(responseJson);
        }
    }

    // Usage
    var client = new PricingClient("YOUR_API_TOKEN");
    var request = new PriceRequest
    {
        EnvironmentId = Guid.Parse("123e4567-e89b-12d3-a456-426614174000"),
        PriceDrivers = new[]
        {
            new PriceDriver { Name = "product", Value = "laptop" },
            new PriceDriver { Name = "customer_tier", Value = "premium" }
        },
        CurrencyThreeLetterCode = "USD",
        PricingDate = DateTime.Parse("2024-01-15T10:00:00Z")
    };

    var price = await client.GetPriceAsync(request);
    Console.WriteLine($"Price: {price.Amount.Amount} {price.Amount.CurrencyThreeLetterCode}");
import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.net.URI;
    import java.time.Duration;
    import com.fasterxml.jackson.databind.ObjectMapper;

    public class PricingClient {
        private final HttpClient httpClient;
        private final ObjectMapper objectMapper;
        private final String apiToken;
        private static final String BASE_URL = "https://api.grula.net";

        public PricingClient(String apiToken) {
            this.httpClient = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();
            this.objectMapper = new ObjectMapper();
            this.apiToken = apiToken;
        }

        public PriceResponse getPrice(PriceRequest request) throws Exception {
            String requestBody = objectMapper.writeValueAsString(request);
        
            HttpRequest httpRequest = HttpRequest.newBuilder()
                .uri(URI.create(BASE_URL + "/api/v1/price"))
                .header("Authorization", "Bearer " + apiToken)
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(requestBody))
                .build();

            HttpResponse<String> response = httpClient.send(httpRequest, 
                HttpResponse.BodyHandlers.ofString());
        
            if (response.statusCode() == 200) {
                return objectMapper.readValue(response.body(), PriceResponse.class);
            } else {
                throw new RuntimeException("API call failed: " + response.statusCode());
            }
        }
    }

    // Usage
    PricingClient client = new PricingClient("YOUR_API_TOKEN");
    PriceRequest request = new PriceRequest();
    request.setEnvironmentId(UUID.fromString("123e4567-e89b-12d3-a456-426614174000"));
    request.setPriceDrivers(Arrays.asList(
        new PriceDriver("product", "laptop"),
        new PriceDriver("customer_tier", "premium")
    ));
    request.setCurrencyThreeLetterCode("USD");
    request.setPricingDate(Instant.parse("2024-01-15T10:00:00Z"));

    PriceResponse price = client.getPrice(request);
    System.out.println("Price: " + price.getAmount().getAmount() + " " + 
        price.getAmount().getCurrencyThreeLetterCode());

Get Multiple PricesPOST

Calcula múltiples precios en una sola solicitud. Eficiente para operaciones de precios masivos con un máximo de 100 solicitudes de precios por llamada.

Endpoint

POST /api/v1/prices
curl -X POST "https://api.grula.net/api/v1/prices" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "environmentId": "123e4567-e89b-12d3-a456-426614174000",
    "priceRequests": [
      {
        "priceDrivers": [
          {"name": "product", "value": "laptop"},
          {"name": "customer_tier", "value": "premium"}
        ],
        "currencyThreeLetterCode": "USD",
        "pricingDate": "2024-01-15T10:00:00Z"
      },
      {
        "priceDrivers": [
          {"name": "product", "value": "desktop"},
          {"name": "customer_tier", "value": "standard"}
        ],
        "currencyThreeLetterCode": "EUR",
        "pricingDate": "2024-01-15T10:00:00Z"
      }
    ]
  }'
import requests

    url = "https://api.grula.net/api/v1/prices"
    headers = {
        "Authorization": "Bearer YOUR_API_TOKEN",
        "Content-Type": "application/json"
    }

    payload = {
        "environmentId": "123e4567-e89b-12d3-a456-426614174000",
        "priceRequests": [
            {
                "priceDrivers": [
                    {"name": "product", "value": "laptop"},
                    {"name": "customer_tier", "value": "premium"}
                ],
                "currencyThreeLetterCode": "USD",
                "pricingDate": "2024-01-15T10:00:00Z"
            },
            {
                "priceDrivers": [
                    {"name": "product", "value": "desktop"},
                    {"name": "customer_tier", "value": "standard"}
                ],
                "currencyThreeLetterCode": "EUR",
                "pricingDate": "2024-01-15T10:00:00Z"
            }
        ]
    }

    response = requests.post(url, headers=headers, json=payload)
    prices = response.json()

    for i, price in enumerate(prices):
        print(f"Price {i+1}: {price['amount']['amount']} {price['amount']['currencyThreeLetterCode']}")
const axios = require('axios');

    const getBatchPrices = async () => {
      try {
        const response = await axios.post('https://api.grula.net/api/v1/prices', {
          environmentId: '123e4567-e89b-12d3-a456-426614174000',
          priceRequests: [
            {
              priceDrivers: [
                { name: 'product', value: 'laptop' },
                { name: 'customer_tier', value: 'premium' }
              ],
              currencyThreeLetterCode: 'USD',
              pricingDate: '2024-01-15T10:00:00Z'
            },
            {
              priceDrivers: [
                { name: 'product', value: 'desktop' },
                { name: 'customer_tier', value: 'standard' }
              ],
              currencyThreeLetterCode: 'EUR',
              pricingDate: '2024-01-15T10:00:00Z'
            }
          ]
        }, {
          headers: {
            'Authorization': 'Bearer YOUR_API_TOKEN',
            'Content-Type': 'application/json'
          }
        });
    
        response.data.forEach((price, index) => {
          console.log(`Price ${index + 1}: ${price.amount.amount} ${price.amount.currencyThreeLetterCode}`);
        });
    
        return response.data;
      } catch (error) {
        console.error('Error fetching batch prices:', error.response?.data || error.message);
      }
    };

    getBatchPrices();

Ejemplos de respuesta

Entender la estructura de las respuestas de API te ayuda a integrar datos de precios efectivamente en tus aplicaciones.

Price Response

{
  "amount": {
    "amount": 1299.99,
    "currencyThreeLetterCode": "USD"
  },
  "priceComponents": [
    {
      "pricingPolicyId": "123e4567-e89b-12d3-a456-426614174000",
      "amount": {
        "amount": 1499.99,
        "currencyThreeLetterCode": "USD"
      }
    },
    {
      "priceAdjustmentPolicyId": "456e7890-e89b-12d3-a456-426614174001",
      "amount": {
        "amount": -200.00,
        "currencyThreeLetterCode": "USD"
      },
      "priceAdjustmentPolicyActionName": "Premium Customer Discount",
      "priceAdjustmentPolicyValue": 0.15
    }
  ]
}

Gestión de errores

La API utiliza códigos de estado HTTP estándar para indicar el éxito o fallo de las solicitudes. Aquí están los códigos de estado más comunes que encontrarás.

Códigos de estado HTTP

200
Success - Solicitud completada correctamente
201
Created - Recurso creado correctamente
400
Bad Request - Parámetros de solicitud inválidos
401
Unauthorized - Token de API inválido o faltante
404
Not Found - Recurso no encontrado
409
Conflict - El recurso ya existe o hay un conflicto de versión
500
Internal Server Error - Se ha producido un error en el servidor