Skip to content

Credential fields are typed non-nullable, so any redacted secret makes the whole response undecodable #4

Description

@riteshptl21

Package: vapi/vapi 2.0.0
Environment: PHP 8.5.5

Summary

The SDK declares credential fields as non-nullable string. The Vapi API redacts
secrets on read and returns null for them. Deserializing any response that
contains one throws a TypeError.

Because list endpoints decode the entire array in one pass, a single affected
record makes the whole call fail. There is no partial result — the caller gets
an exception instead of a list.

Reproduction

Self-contained. No API key and no account needed:

require 'vendor/autoload.php';

Vapi\Types\SipAuthentication::jsonDeserialize([
    'realm'    => 'sip.vapi.ai',
    'username' => 'user',
    'password' => null,   // what the API returns: secrets are redacted on read
]);

Actual:

TypeError: Cannot assign null to property Vapi\Types\SipAuthentication::$password
           of type string
  in vendor/vapi/vapi/src/Types/SipAuthentication.php:40

Expected: the object deserializes with password as null.

How it shows up in practice

An account containing one BYO SIP number is enough to break the entire
phone-number listing:

$client->phoneNumbers->list(new ListPhoneNumbersRequest);
// TypeError — no numbers returned at all, not a partial list

SipAuthentication is reached through SipTrunkGateway → BYO phone number, so
the failure surfaces on an endpoint that has nothing obviously to do with SIP
credentials. That makes it hard to attribute: the caller asked for phone
numbers and got a type error about a password.

Cause

src/Types/SipAuthentication.php:

public string $password;          // line 26

public function __construct(array $values) {
    $this->realm    = $values['realm'] ?? null;
    $this->username = $values['username'];
    $this->password = $values['password'];   // line 40 — no null tolerance
}

realm is correctly ?string. password is not, but it is the field the API is
guaranteed not to return, being a secret.

Scope

This is not specific to SipAuthentication. 93 of 1784 type files declare a
non-nullable credential field:

Field Type files
public string $apiKey 75
public string $credentialId 7
public string $awsSecretAccessKey 3
public string $apiSecret 2
$password, $token, $accessToken, $sessionToken, $secretKey, $secretAccessKey, $clientSecret, $tokenUri 1 each

(Some files carry two of these fields, e.g. VonageCredential has both apiKey
and apiSecret.)

Examples carrying $apiKey: HumeCredential, SmallestAiCredential,
TogetherAiCredential, CreateHumeCredentialDto, CreateXAiCredentialDto.

Any endpoint returning an object with a redacted credential fails the same way,
so this is likely to affect credential listing and assistant/call payloads that
embed provider credentials — not just phone numbers.

Suggested fix

Type read-side credential fields as nullable:

public ?string $password;
// ...
$this->password = $values['password'] ?? null;

A field the API never returns on read cannot correctly be non-nullable on a
response type. If the same class is used for both requests and responses, the
write path can keep requiring the value at the call site while the property
itself tolerates null when decoding.

A narrower alternative is to make the decoder tolerant of missing/redacted
credential fields, but the type declarations would still be describing something
the API does not do.

Workaround for anyone hitting this

Bypass the typed layer for the affected endpoint and fetch the plain JSON with a
direct HTTP call (e.g. Guzzle against GET /phone-number with the bearer token).
Fine when you only need identifiers, but it gives up the type safety the SDK
exists to provide.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions