Publiczne API v0.3.0-preview.1 · OpenAPI 3.1.2
Quickstart
Najpierw utwórz klienta w panelu organizacji. Zapisz jednorazowo pokazany sekret w secret managerze; InvoiceIQ nie pokaże go ponownie.
1. Machine-to-machine
Utwórz klienta typu M2M wyłącznie ze scope’em customers:read. Poniższy smoke test używa rzeczywistej operacji, nie testowego endpointu.
export INVOICEIQ_BASE_URL='https://twoj-issuer.example'
export INVOICEIQ_CLIENT_ID='identyfikator-z-panelu'
read -r -s -p 'Client secret: ' INVOICEIQ_CLIENT_SECRET
TOKEN_RESPONSE="$({
printf 'user = "%s:%s"\n' "$INVOICEIQ_CLIENT_ID" "$INVOICEIQ_CLIENT_SECRET"
printf 'data = "grant_type=client_credentials"\n'
printf 'data = "scope=customers:read"\n'
} | curl --silent --show-error --fail-with-body --config - \
"$INVOICEIQ_BASE_URL/oauth/token")"
unset INVOICEIQ_CLIENT_SECRET
ACCESS_TOKEN="$(printf '%s' "$TOKEN_RESPONSE" | jq -er '.access_token')"
printf 'header = "Authorization: Bearer %s"\n' "$ACCESS_TOKEN" |
curl --silent --show-error --fail-with-body --config - \
"$INVOICEIQ_BASE_URL/api/v1/customers"
unset ACCESS_TOKEN TOKEN_RESPONSE
HTTP Basic jest profilem zalecanym. Runtime Passport akceptuje również client_secret_post, ale quickstart nie umieszcza sekretu w body, URL ani committed pliku.
2. Delegated authorization
Utwórz poufnego klienta delegated z dokładnym HTTPS redirect URI i ustaw zmienne bazowego URL/client ID na jego wartości. Przechowuj state i verifier po stronie backendu konsumenta, powiązane z jego sesją.
STATE="$(openssl rand -hex 32)"
VERIFIER="$(openssl rand -base64 96 | tr '+/' '-_' | tr -d '=\n' | cut -c1-96)"
CHALLENGE="$(printf '%s' "$VERIFIER" | openssl dgst -binary -sha256 | openssl base64 -A | tr '+/' '-_' | tr -d '=')"
export STATE VERIFIER CHALLENGE
export INVOICEIQ_REDIRECT_URI='https://consumer.example/oauth/callback'
AUTH_URL="$(php -r '
echo getenv("INVOICEIQ_BASE_URL")."/oauth/authorize?".http_build_query([
"response_type" => "code",
"client_id" => getenv("INVOICEIQ_CLIENT_ID"),
"redirect_uri" => getenv("INVOICEIQ_REDIRECT_URI"),
"scope" => "customers:read",
"state" => getenv("STATE"),
"code_challenge" => getenv("CHALLENGE"),
"code_challenge_method" => "S256",
]);
')"
printf 'Otwórz w przeglądarce: %s\n' "$AUTH_URL"
# Backend callbacku musi przerwać flow, jeżeli zwrócone state != $STATE.
read -r -p 'Authorization code po sprawdzeniu state: ' AUTHORIZATION_CODE
read -r -s -p 'Client secret: ' INVOICEIQ_CLIENT_SECRET
TOKEN_RESPONSE="$({
printf 'user = "%s:%s"\n' "$INVOICEIQ_CLIENT_ID" "$INVOICEIQ_CLIENT_SECRET"
printf 'data-urlencode = "grant_type=authorization_code"\n'
printf 'data-urlencode = "redirect_uri=%s"\n' "$INVOICEIQ_REDIRECT_URI"
printf 'data-urlencode = "code=%s"\n' "$AUTHORIZATION_CODE"
printf 'data-urlencode = "code_verifier=%s"\n' "$VERIFIER"
} | curl --silent --show-error --fail-with-body --config - \
"$INVOICEIQ_BASE_URL/oauth/token")"
unset INVOICEIQ_CLIENT_SECRET AUTHORIZATION_CODE VERIFIER CHALLENGE STATE AUTH_URL
InvoiceIQ wymaga zalogowanej, zweryfikowanej przez MFA osoby, aktywnego członkostwa oraz ekranu consent.
Po callbacku konsument najpierw porównuje zwrócone state stałoczasowo. Przy mismatch kończy przepływ bez wymiany kodu.
Kod, redirect URI i code_verifier są następnie wysyłane do /oauth/token, a poufny klient nadal uwierzytelnia się przez HTTP Basic.
3. Mutacje i procesy asynchroniczne
- Generuj nowy, losowy
Idempotency-Keydla intencji biznesowej i zachowuj go do bezpiecznego retry. - Zapisuj zwrócony
ETag; wyślij go jakoIf-Matchprzy zmianie wersji. - Preview nie jest akceptacją. Wystawienie, wysłanie i retry KSeF mają oddzielne approval intent oraz hosted confirmation.
- Po timeoutach uzgadniaj stan przez GET i webhook; nie twórz automatycznie drugiego dokumentu.