Dokumentacja API cenowego Grula

Podłącz system ERP, sklep B2B lub aplikację ofertową do REST API Grula. Znajdziesz tu uwierzytelnianie, wycenę pojedynczą i wsadową oraz przykładowe żądania i odpowiedzi.

Szybki start

Przygotuj token API, wybierz endpoint i wyślij pierwsze żądanie o cenę.

Uwierzytelnianie

Do żądania dodaj nagłówek Authorization z tokenem Bearer wygenerowanym w panelu Grula.

Authorization: Bearer YOUR_API_TOKEN

Base URL

https://api.grula.net

Kluczowe koncepcje

Polityki cenowe (cenniki)

Polityka cenowa przechowuje ceny bazowe dla produktów i warunki ich zastosowania. Pełni rolę cennika używanego przez silnik wyceny.

Korekty ceny (rabaty i opłaty)

Reguły korekty zmieniają cenę bazową, gdy spełnione są określone warunki, na przykład grupa klienta lub wielkość zamówienia.

Oblicz pojedynczą cenęPOST

Wyślij czynniki cenowe, walutę i opcjonalną datę wyceny. API zwróci cenę obliczoną według pasujących polityk.

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());

Oblicz wiele cenPOST

Wyślij do 100 zestawów czynników cenowych w jednym żądaniu, aby uzyskać wyniki wyceny wsadowej.

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();

Przykłady odpowiedzi

Przykładowa odpowiedź pokazuje wynik wyceny i składniki, które wpłynęły na cenę.

Odpowiedź z ceną

{
  "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
    }
  ]
}

Obsługa błędów

Kody HTTP informują, czy żądanie się powiodło oraz co poprawić w razie błędu.

Kody statusu HTTP

200
Żądanie zakończone pomyślnie
201
Zasób został utworzony
400
Nieprawidłowe parametry żądania
401
Brak tokena API lub token jest nieprawidłowy
404
Nie znaleziono zasobu
409
Konflikt danych lub wersji zasobu
500
Błąd po stronie serwera