Authentication
Request, use, and renew OAuth tokens.
Auth issues OAuth 2.0 tokens at https:/.
Send the token in the Authorization: Bearer header.
POST / connect/ token200 with access_token and expires_inGET / v1/ catalog/ products with Bearer200 with the dataApplication credentials
An application created in the dashboard gives you a client_id and a
client_secret. The secret lives only on your server, never in a browser or a
distributed app.
API keys created with POST / are not OAuth tokens: Admin,
Storefront, and Auth reject them.
Token for an Admin integration
Use client_credentials with the api_admin scope:
curl -X POST https://auth.ecomiq.pe/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$ECOMIQ_CLIENT_ID" \
-d "client_secret=$ECOMIQ_CLIENT_SECRET" \
-d "scope=api_admin"{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6...",
"token_type": "Bearer",
"expires_in": 3600
}expires_in is the lifetime in seconds.
Use the token
curl "https://api.ecomiq.pe/api/v1/catalog/products?limit=25" \
-H "Authorization: Bearer $ECOMIQ_TOKEN"The store and, when it applies, the seller come from the token. See Organization, store, and seller.
Grants
| Grant | Use |
|---|---|
client_credentials | A server acts as the application. Requires a confidential client. |
authorization_code | A person authorizes the application. See User authorization. |
refresh_token | Renews a session, if the application has this grant. |
Each application accepts only the grants and scopes configured for it.
Renewal
client_credentials has no refresh token: request a new one before it expires.
Cache the token with a one-minute margin.
let cached: { token: string; expiresAt: number } | undefined;
export async function getToken(): Promise<string> {
if (cached && Date.now() < cached.expiresAt - 60_000) {
return cached.token;
}
const body = new URLSearchParams({
grant_type: "client_credentials",
client_id: process.env.ECOMIQ_CLIENT_ID!,
client_secret: process.env.ECOMIQ_CLIENT_SECRET!,
scope: "api_admin",
});
const response = await fetch("https://auth.ecomiq.pe/connect/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body,
});
if (!response.ok) throw new Error(`OAuth HTTP ${response.status}`);
const payload = await response.json();
cached = {
token: payload.access_token,
expiresAt: Date.now() + payload.expires_in * 1000,
};
return cached.token;
}If several processes share credentials, coordinate renewal so they don't request tokens in a burst.
Authentication failures
401: the endpoint did not receive a valid credential.403: the credential is valid, but a scope, permission, or context blocks it./returns OAuth errors such asconnect/ token invalid_clientorinvalid_grant. See Errors.
Don't log tokens, secrets, or full OAuth responses.
Customer sign-in
Chosen in Settings → Checkout → Customer accounts → Sign-in
(checkoutSettings.general.customerLoginMode):
| Mode | Form |
|---|---|
hosted | Auth page with the store's name and logo. Default. |
storefront | Inside the store, styled by the theme. |
In both modes Auth verifies the email and code. Switching modes keeps the accounts. A customer and an Admin user can share an email address.
- The store server configures the OAuth client with
POST /and receivesv1/ customer/ auth/ config loginMode,captcha, and the OAuth settings. - In
storefrontmode, it requests the code withPOST /.v1/ customer-auth/ challenges - The SDK exchanges the code (Authorization Code with PKCE) and stores the session in a secure cookie. The theme never stores tokens.
CAPTCHA is optional: Cloudflare Turnstile or Google reCAPTCHA v2. Attempt limits always apply.
Registration details
Chosen in Settings → Checkout → Registration details
(checkoutSettings.general.customerRegistration). firstName, lastName,
phone, and dateOfBirth can be hidden (not asked), optional, or
required. The default is hidden.
- After email verification, the server reads
GET /: fields, values, andv1/ customer/ registration requiresCompletion. - When
requiresCompletionistrue, the theme shows the form before the account or checkout. - The server sends the details to
POST /. If every field is optional,v1/ customer/ registration {}is enough.
Rules:
- While registration is pending, account APIs and order creation return
Customer.RegistrationRequired. - The server always validates: hiding a field in the theme doesn't skip it.
- An existing customer sees the form again only when a
requiredfield is missing. dateOfBirthcan't be later than today in the store.PATCH /can't clear av1/ customer requiredfield.- The welcome email is sent once, when registration completes.
- Guest checkout is a separate setting.
Last updated: