juspay/hyperswitch · error · Error

API Key create call failed with status ${response.status} an

Error message

API Key create call failed with status ${response.status} and message: "${response.body.error.message}"

What it means

Thrown by the apiKeyCreateTest command (cypress-tests/cypress/support/commands.js:1383) when POST {baseUrl}/api_keys/{merchantId} returns non-200. The call authenticates with globalState.get('adminApiKey') (the admin key, not the merchant key), sets expiration to tomorrow via isoTimeTomorrow(), and on success stores apiKeyId/api_key into globalState — so this failure cascades into every later command that needs a merchant api-key.

Source

Thrown at cypress-tests/cypress/support/commands.js:1383

    cy.wrap(response).then(() => {
      if (response.status === 200) {
        expect(response.body.merchant_id).to.equal(merchantId);
        expect(response.body.description).to.equal(
          apiKeyCreateBody.description
        );

        // API Key assertions are intentionally excluded to avoid being exposed in the logs
        expect(response.body).to.have.property(keyIdType).and.to.include(keyId)
          .and.to.not.be.empty;

        globalState.set("apiKeyId", response.body.key_id);
        globalState.set("apiKey", response.body.api_key);

        cy.task("setGlobalState", globalState.data);
      } else {
        // to be updated
        throw new Error(
          `API Key create call failed with status ${response.status} and message: "${response.body.error.message}"`
        );
      }
    });
  });
});

Cypress.Commands.add("apiKeyUpdateCall", (apiKeyUpdateBody, globalState) => {
  const merchantId = globalState.get("merchantId");
  const apiKeyId = globalState.get("apiKeyId");
  // We do not want to keep API Key forever,
  // so we set the expiry to tomorrow as new merchant accounts are created with every run
  const expiry = isoTimeTomorrow();

  // Update request body
  apiKeyUpdateBody.expiration = expiry;

  cy.request({

View on GitHub (pinned to 9b8b89dc37)

Solutions

  1. Verify the admin API key env var is set, current, and belongs to the same environment as baseUrl
  2. Confirm globalState.get('merchantId') came from a successful merchant-create step in this run
  3. Grab the logged x-request-id and inspect the server logs for the exact rejection
  4. Check the apiKeyCreateBody fixture (description/name) matches the current api_keys schema
  5. Fix credentials and re-run — all subsequent steps depend on apiKeyId/api_key this command sets
Defensive patterns

Strategy: try-catch

Validate before calling

if (!globalState.get('adminApiKey')) {
  throw new Error('adminApiKey missing from globalState — check env/secrets before apiKeyCreateTest');
}

Try / catch

cy.on('fail', (err) => {
  if (err.message.includes('API Key create call failed')) {
    throw new Error(`Setup gate: API key provisioning failed — every later step needs apiKey/apiKeyId. Root cause: ${err.message}`);
  }
  throw err;
});

Prevention

When it happens

Trigger: Invalid or expired adminApiKey (401); merchantId missing or deleted so the URL targets a non-existent resource (404); server rejecting the expiration/description body (400); 5xx from the api_keys service; validateEnv(baseUrl, 'key_id') misconfiguration producing a malformed request.

Common situations: The admin API key env var was rotated between runs; CI secrets not injected so adminApiKey is undefined; the merchant record was purged on the target environment; the env key-id prefix doesn't match what the environment issues, breaking the success-path assertions after a 200.

Related errors


AI-assisted analysis of juspay/hyperswitch@9b8b89dc37 (2026-08-16). Data as JSON: /api/errors/bcbd9a650e664885. Report an issue: GitHub.